poj1185 炮兵阵地 经典状态压缩dp

这个题目和上一个种玉米的是一个类型,都是状态dp,用二进制位来表示当前的一个状态值,只不过比上一个稍微复杂了一点,需要用三维的数组来保存当前state。

题目:在一个N*M的矩阵上布置炮兵部队,只有平原可以布置,然后每个炮兵部队都有一个攻击范围,它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。

问:如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区

域内最多能够摆放多少我军的炮兵部队?

由于是求的最多能放置的炮兵个数,就是求某一个状态下,它对应的炮兵个数最多,所以就想到dp方程肯定是那种dp[i+1]=max{dp[i-1]..}的形式,又考虑到每一行

的状态只和前两行有关系,所以考虑用dp来做,下面考虑如何用二进制位来表示一个状态及转移方程。

对于原始的矩阵,我们用1来表示可以放置炮兵,即对应图中的P,这样每一行都有一个可以放置炮兵的状态,存到rstate[N]中,用来check该行的状态是否合法。

由于当前行和前两行有关系,所以得用3维矩阵来保存一个状态下最多的炮兵个数,用dp[i][curst][prest]表示当前第i行状态对curst,前一行状态为prest的最大炮兵数。

转移方程为dp[i][curst][prest]=max{dp[i-1][prest][preprest]},这样求到最后一行之后,答案就是最后一行所有状态中最大的那个。程序初始化的时候需要对第一行

进行预处理,设置dp[0][st][0]=st合法&st中1的个数。这样进行下面的计算的时候,由于0状态肯定是和所有状态兼容的,所以就不会影响计算结果。

代码如下:

View Code
#include <iostream>

#include <stdio.h>

using namespace std;

const int N = 101;

const int M=11;

const int MAXS = 61;

char matrix[N][M];

int dp[N][MAXS][MAXS];

int vst[MAXS];

int num[MAXS];

int rstate[N];

int vnum = 0, n = 0, m = 0;

int getnum(int i)

{

    int ret = 0;

    while(i)

    {

        i &= i - 1;

        ++ret;

    }

    return ret;

}

void initstate()

{

    vnum = 0;

    for(int i = 0; i < (1<<m); ++i)

    {

        if(!(i&(i<<1)) && !(i&(i<<2)))

        {

            vst[vnum] = i;

            num[vnum++] = getnum(i);

        }

    }

}

int main()

{

    int i = 0, j = 0, k = 0, t = 0;

    while(EOF != scanf("%d%d", &n, &m))

    {

        for(i = 0; i < n; ++i)

        {

            rstate[i] = 0;

            scanf("%s", matrix[i]);

            for(j = 0; j < m; ++j)

            {    

                if('P' == matrix[i][j])

                {

                    rstate[i] += (1<<(m-j-1));

                }

            }

        }

        for(i = 0; i < n; ++i)

            for(j = 0; j < MAXS; ++j)

                for(k = 0; k < MAXS; ++k)

                    dp[i][j][k] = -1;

        initstate();

        for(i = 0; i < vnum; ++i)

            if(!(vst[i]&(~rstate[0])))

                dp[0][i][0] = num[i];

       //dp[i][j][k] = max{dp[i][j][k], dp[i-1[k][t]]+num[j]}

       for(i = 1; i < n; ++i)

       {

           for(j = 0; j < vnum; ++j)// state of row i

           {

               if((~rstate[i])&vst[j])

                   continue;

               for(k = 0; k < vnum; ++k)//state of row i-1

               {

                   if((~rstate[i-1])&vst[k])

                       continue;

                   if(vst[j]&vst[k])

                       continue;

                   for(t = 0; t < vnum; ++t)//state of row i-2

                   {

                     if(vst[j]&vst[t])

                         continue;

                     if(-1 == dp[i-1][k][t])

                         continue;

                     dp[i][j][k]=(dp[i][j][k]>=dp[i-1][k][t]+num[j])?dp[i][j][k]:dp[i-1][k][t]+num[j];

                   }

               }

           }

       }

       int ret = 0;

       for(i = 0; i < vnum; ++i)

       {

           for(j = 0; j < vnum; ++j)

           {

               if(dp[n-1][i][j]>ret)

                   ret = dp[n-1][i][j];

           }

       }

       printf("%d\n", ret);

    }

    return 0;

}

 

你可能感兴趣的:(poj)