您的位置:首页 > 其它

poj 1185 炮兵阵地 三进制状态压缩,DFS,滚动数组

2013-01-16 15:37 405 查看
  我们把 放置在 第 I 行的炮兵 称为 I 行炮兵, 通过观察我们可以得出, 第I行炮兵只受 I-1 行,I-2行的 放置情况影响.

  对于第Y列,有三种情况:

     P[x] = 0,   i-1 行 空 i-2 行 空    

     P[x] = 1,    i-1 行 空, i-2 行放置了炮兵

     P[x] = 2,   i-1 行 放置炮兵 (因为 此行放置了炮兵, 哪怕 I-2行 空,对于 I行而言,也毫无意义)

  因为这题与 1038不同, 若当前位置为平原, 只影响当前层,而对下一层无影响,所以我们不能将 平原和高山 情况合并到状态中, 其实直接单点考虑也没事.

  因为一共M列,每一列都由一个 三进制数表示, 则(I-1,I-2)的放置情况可以通过 一串三进制的序列表示,为 P1,P2,...,Pm,称为放置序列

  

  我们可以通过 (I,I-1)的放置情况得出 I+1 层放置方案, 而且要更新得到 (I+1,I)放置序列

  其实去掉 I-1 层的影响就可以了, 这也是为何 将 I行 放置炮兵时,P[x] = 2, 因为其还能向下影响 两行,随着行数增多,影响逐渐变小

  (I+1,I)层 放置序列 Q[y] = P[y] > 0 ? P[y]-1 : 0

  定义状态 dp(I,J),表示 第I行, 状态J 表示 (I,I-1)层的放置情况 下最大 炮兵部署数量

  方程转移有三种情况:

    一,当前层不放置任何炮兵,此时 dp(i+1,k) = dp(i,j)

    二,对于当前列 y, 可以不放置,考虑y+1开始放置

    三,若 P[y] = 0, 则放置炮兵并设定状态 k = k + 2*3^(y-1) , 继续考虑 y+3列

解题代码

View Code

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX(a,b) (a)>(b)?(a):(b)

int dp[2][60000], A[11], P[11], Q[11];
char mp[110][15];
int n, m, mask;

int GetState(int f[])
{
int k = 0;
for(int i = 1; i <= m; i++)
k += f[i]*A[i-1];
return k;
}
int GetBack( int x, int f[] )
{
for(int i = 1; i <= m; i++)
{    f[i] = x%3; x /= 3; }
}
void input()
{
A[0] = 1;
for(int i = 1; i <= 10; i++)
A[i] = 3*A[i-1];

for(int i = 1; i <= n; i++)
scanf("%s", mp[i]+1 );
}

void dfs( int i, int x, int num )
{
if( x > m ) return;
int cur = (i+1)&1, nxt = i&1, k = GetState(Q);
//当前层 可以不放置炮兵
dp[nxt][k] = MAX( dp[nxt][k], dp[cur][GetState(P)] );

//情况一,当前列x不放,考虑x+1列
if( x < m ) dfs( i, x+1, num );
//情况二,若当前位置可以放置,且(i+1,x)位置为平原
if( (mp[i][x]=='P') && (P[x]==0) && (Q[x]==0))
{
//    printf("x = %d,y = %d, ch = %c\n", i+1,x,mp[i+1][x]);
Q[x] = 2;
int kk = GetState(Q);
dp[nxt][kk] = MAX( dp[nxt][kk], num+1 );
dfs( i, x+3, num+1 );
Q[x] = 0;
}

}
void solve()
{
memset( P, 0, sizeof(P) );
memset( dp, 0xff, sizeof(dp) );
dp[0][0] = 0;

mask = A[m];
for(int i = 1; i <= n; i++)
{
int cur = (i+1)&1, nxt = i&1;
memset( dp[nxt], 0xff, sizeof(dp[nxt]) );
for(int j = 0; j < mask; j++)
{
if( dp[cur][j] == -1 ) continue;

GetBack( j, P );
for(int x = 1; x <= m; x++)
Q[x] =( (P[x] > 0) ? (P[x]-1) : 0 );
dfs( i, 1, dp[cur][j] );
}
}
int ans = 0;
for(int i = 0; i < mask; i++)
ans = MAX( ans, MAX( dp[0][i],dp[1][i] ) );
printf("%d\n", ans );
}

int main()
{
while( scanf("%d%d",&n,&m) != EOF)
{
input();
solve();
}
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: