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;
}
原文地址:https://www.cnblogs.com/buptLizer/p/2651881.html