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

  我们把 放置在 第 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;
}

 

posted @ 2013-01-16 15:37  yefeng1627  阅读(499)  评论(0编辑  收藏  举报

Launch CodeCogs Equation Editor