标签:状压dp
Description
Input
Output
Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
这题属于状压dp,花了很长时间终于做出来了(笑),一开始看错题目,还以为求总的方案数= =。
我的做法是先把图每一行都压缩成一个十进制数,‘P‘变成0,‘Q‘变成‘1‘,这么写是为了之后判断能不能放炮兵提供方便(因为这样表示如果用&运算符算出来是1的只有放炮兵(1)和‘Q‘(1)这种情况,其他情况下运算后都是0,可以动手画一下),然后枚举所有每一行所有可能的摆放情况(j从0~(1<<m)-1),先判断是不是两格以内都是1,用if( (j&(j<<1)) || (j&(j<<2)))来判断,然后再判断当前的j和temp是不是有某位同时为1的情况,用if(j&temp)判断。用num1[i][j]来表示第i行第j种状态所压缩后的十进制数,用num1[i]来表示第i行所有状态的总个数,用soldier[i][j]来表示第i行第j种状态的该行炮兵总数,用dp[i][j][k]来表示第i行第j中状态下第i-1行第k中状态下的最大炮兵数。
先对第一行和第二行进行初始化,然后从第三行开始依次进行动规,转移方程是dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][h]+soldier[i][j]);
最后求值的时候要注意,如果n==1或者n==2要单独讨论,如果n>3的时候要注意最大值不一定是dp[n][j][k],因为可能最大值不是在最后一行取到的,所以要把ans的取值放在中间。
#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; int num1[120],num[120][70],dp[120][70][70],n,m,soldier[120][70]; void hang(int i,int temp) { int t=0,j,k,sum; for(j=0;j<(1<<m);j++){ if( (j&(j<<1)) || (j&(j<<2)))continue; // || ((j<<1)&(j<<2))||(j&(j>>1)) || (j&(j>>2)) || ((j>>1)&(j>>2)) if(j&temp)continue; t++;num[i][t]=j; k=j;sum=0; while(k>0){ if(k%2==1)sum++; k/=2; } soldier[i][t]=sum; } num1[i]=t; } int main() { int i,j,temp,k,h,sum,sum1,ans; char s[20]; while(scanf("%d%d",&n,&m)!=EOF) { memset(num1,0,sizeof(num1)); memset(num,0,sizeof(num)); memset(dp,0,sizeof(dp)); memset(soldier,0,sizeof(soldier)); for(i=1;i<=n;i++){ scanf("%s",s); temp=0; for(j=0;j<m;j++){ if(s[j]=='P'){ temp=temp*2; } else if(s[j]=='H'){ temp=temp*2+1; } } hang(i,temp); } ans=0; for(j=1;j<=num1[1];j++){ dp[1][j][0]=soldier[1][j]; } if(n==1){ for(j=1;j<=num1[1];j++){ ans=max(ans,dp[1][j][0]); } printf("%d\n",ans);continue; } ans=0; for(j=1;j<=num1[2];j++){ for(k=1;k<=num1[1];k++){ if(num[2][j]&num[1][k])continue; dp[2][j][k]=soldier[2][j]+soldier[1][k]; ans=max(ans,dp[2][j][k]); } } if(n==2){ printf("%d\n",ans);continue; } ans=0; for(i=3;i<=n;i++){ for(j=1;j<=num1[i];j++){ for(k=1;k<=num1[i-1];k++){ if(num[i][j]&num[i-1][k])continue; for(h=1;h<=num1[i-2];h++){ if( (num[i][j]&num[i-2][h]) || (num[i-1][k]&num[i-2][h]) )continue; dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][h]+soldier[i][j]); ans=max(ans,dp[i][j][k]); } } } } printf("%d\n",ans); } return 0; }
标签:状压dp
原文地址:http://blog.csdn.net/kirito_acmer/article/details/46582483