擦,真不应该让这个题目弄这么久
就是一个比较简单的状态DP,先预处理出每一行的可行情况,然后因为当前行是和前两行有关系的,果断不能只用个两维啊,我一开始Dp数组开个两维,只记录当前行的状态,结果在枚举前面行的时候果断就不行啊,因为你枚举了上一行那上一行的前两行又要枚举,果断不行啊,我居然还照着这个思路全部写完并且过了样例,还提交WA了很久都没反应过来
至少开三维,dp[i][j][k]记录当前行为j状态,i-1行为k状态时的最大值,那么dp[i][j][k]=max(本身,dp[i-1][k][w]+cot[j]),其中状态和某个状态的含1的个数都预处理好了,j,k,w
都是状态编号,w为i-2行的状态,cot记录某状态的1的个数,这样就果断不会漏情况了啊
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int ma[105]; int dp[110][105][105]; int sum; int test[1<<11],cot[1<<11]; int num; int m,n; bool ok(int sta1,int sta) { //if ((sta&(sta<<1)) || (sta & (sta<<2))) return 0; if (sta & sta1) return 0; return 1; } void init() { int all=1<<m; num=0; for (int i=0;i<all;i++) { if (i&(i<<1) || i&(i<<2)) continue; test[num]=i; int tmp=i,tc=0; while (tmp) { tc++; tmp&=tmp-1; } cot[num++]=tc; } } int main() { char ch[15]; while (scanf("%d%d",&n,&m)!=EOF) { init(); memset(dp,0,sizeof dp); for (int i=1; i<=n; i++) { scanf("%s",ch); //puts(ch); ma[i]=0; for (int j=0; j<m; j++) { if (ch[j]=='H') ma[i]|=1<<j; } } sum=0; for (int i=0; i<num; i++) { if (ok(ma[1],test[i])==0) continue; dp[1][i][0]=cot[i]; sum=max(sum,dp[1][i][0]); } for (int i=2; i<=n; i++) for (int j=0; j<num; j++){ if (!ok(test[j],ma[i])) continue; for (int k=0;k<num;k++) { if (!ok(test[j],test[k])|| !ok(test[k],ma[i-1])) continue; for (int w=0;w<num;w++) { if (!ok(test[w],ma[i-2])) continue; if (!ok(test[w],test[j])||!ok(test[w],test[k])) continue; if (dp[i-1][k][w]==0) continue; dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][w]+cot[j]); sum=max(sum,dp[i][j][k]); } } } printf("%d ",sum); } return 0; }