状态压缩dp hdu 4539 郑厂长系列故事——排兵布阵

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4539

题目意思:

给一个矩阵,有些位置不能放士兵。每个士兵可以攻击哈密顿距离恰好为2的所有位置。求最多能放多少个士兵,使得士兵之间不冲突。

解题思路:

状态压缩dp.

因为当前位置与前两行有关,所以把相邻两行作为二维状态,枚举第i-2行即可得到第i行的状态。

记状态dp[][i][j]表示当前行状态为i,前一行状态为j时,最多能放的士兵个数。

dp[][i][j]=Cal(i)+max(dp[][j][k]);

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
#define Maxn 110
int dp[2][1<<10][1<<10];
int save[Maxn];

int Cal(int st) //统计1的个数
{
   int res=0;
   while(st)
   {
      if(st&1)
         res++;
      st>>=1;
   }
   return res;
}

int main()
{
   int n,m,tmp;

   while(~scanf("%d%d",&n,&m))
   {
      for(int i=1;i<=n;i++)
      {
         save[i]=0;
         for(int j=0;j<m;j++)
         {
            scanf("%d",&tmp);
            if(!tmp) //0表示不能放,把它作为1考虑 能放作为0考虑
               save[i]|=(1<<j);
         }
      }
      memset(dp,0,sizeof(dp));
      int lim=1<<m;
      for(int i=0;i<lim;i++)
      {
         if((i&(i<<2))||(i&save[1])) //该状态满足
            continue;
         dp[1][i][0]=Cal(i); //只用记住一个状态0,表示一个标志
      }

      int la=1,cur;
      for(int i=2;i<=n;i++)
      {
         cur=la^1;
        // memset(dp[cur],0,sizeof(dp[cur]));
         for(int j=0;j<lim;j++)
         {
            if((j&(j<<2))||(j&save[i])) //该状态满足
               continue;
            for(int k=0;k<lim;k++)
            {
               if((k&(k<<2))||(k&save[i-1])) //该状态满足当前行的要求
                  continue;
               if(j&(k<<1))
                  continue;
               if(j&(k>>1))  //注意要考虑 左移右移两种情况
                  continue;
               dp[cur][j][k]=Cal(j); //该行1的个数
               int Max=0;
               for(int p=0;p<lim;p++)
               {
                  if((p&(p<<2))||(p&save[i-2]))
                     continue;
                  if((k&(p<<1))||(j&p)) //i-2行与i-1行的关系
                     continue;
                  if(k&(p>>1)) //i-2行与i行的关系
                     continue;

                  Max=max(Max,dp[la][k][p]);
               }
               dp[cur][j][k]+=Max;
            }
         }
         la=cur;
      }
      int ans=0;
      for(int i=0;i<lim;i++)
         for(int j=0;j<lim;j++) //注意不能构成关系的全为0
            ans=max(ans,dp[cur][i][j]);
      printf("%d\n",ans);


   }
   return 0;
}




你可能感兴趣的:(动态规划)