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

/*
dp[i][j][k]为第i行的数在第i-1的状态为j第i行的状态为k的最大值
状态转移方程 dp[i][j][k]=max(dp[i][j][k],dp[i-1][s][j]+count(k))
count(k)为状态是k的时候能排的士兵
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 110
#define maxs 61
char str[maxn][maxn];
int dp[maxn][maxs][maxs];
int useful[maxs];//记下有用的状态
int landstatus[maxn];//记录这个图用二进制表示每一行的状态
int n;int m;         //'H'时为1'P'时为0  每一行都有一个状态
                     //那么判断所选状态能否在该行可行的条件就是‘&’是否为0


int count(int x)   //计算状态x所排的士兵
{
    int ans=0;
    int t=x;
    while(t)
    {
        if(t%2)
        ans++;
        t/=2;
    }
    return ans;
}
int init()              //找出所有可行的行状态
{
    int upper=1<<m;
    int k=0;int i;
    for(i=0;i<upper;i++)
    {
        if((i&(i<<1))||(i&(i<<2)))
         continue;
        useful[k++]=i;
    }
    return k;
}
int main()
{
    int i,j,k,s;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(landstatus,0,sizeof(landstatus));
        memset(dp,-1,sizeof(dp));
        for(i=0;i<n;i++)
        {
            scanf("%s",str[i]);
            for(j=0;j<m;j++)
            if(str[i][j]=='H')
            landstatus[i]+=(1<<j);
        }
        int topper=init();
        for(j=0;j<topper;j++)
        {
            if(useful[j]&landstatus[0])
            continue;
            dp[0][0][j]=count(useful[j]);
        }
        for(i=1;i<n;i++)
           for(k=0;k<topper;k++)//枚举第i行的情况
           {
               if(useful[k]&landstatus[i])//判断是否该状态是否在这一行可行
                   continue;
               for(j=0;j<topper;j++)//枚举第i-1的情况
               {
                   if(useful[j]&useful[k])//判断该列是否与前一列冲突
                   continue;
                   for(s=0;s<topper;s++)//枚举第i-2的情况
                   {
                       if(useful[k]&useful[s])//判断该列是否与前两列冲突
                       continue;
                       if(dp[i-1][s][j]==-1)//判断dp[i-1][s][j]是否有可能到达
                       continue;
                       dp[i][j][k]=max(dp[i][j][k],dp[i-1][s][j]+count(useful[k]));
                   }
               }
           }
           int ans=0;
           for(j=0;j<topper;j++)
           for(k=0;k<topper;k++)
           ans=max(ans,dp[n-1][j][k]);
           printf("%d\n",ans);
    }


}

















你可能感兴趣的:(poj1185炮兵阵地 dp+状态压缩 经典题目)