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;

}

 

你可能感兴趣的:(poj)