话说还真没见过能影响两行的状压。想了半天想出来f数组再多一维就能表示,但是没想到怎么才能不爆空间……
也是从这道题里学到的一个妙招。
可以把合法状态存到一个数组里,然后用数组下标来映射状态。感觉好强啊
然后……这题差不多就完了。
#include<cstdio> #include<cctype> #include<algorithm> inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } inline int getlen(int x){ int ans=0; while(x){ if(x&1) ans++; x>>=1; } return ans; } int f[110][70][70]; int s[70],w[70],cnt; int state[110]; int Ans; int main(){ int n=read(),m=read(); int Max=(1<<m)-1; for(int i=1;i<=n;++i){ char c[11]; scanf("%s",c+1); for(int j=1;j<=m;++j){ state[i]=state[i]<<1; if(c[j]=='H') state[i]++; } } for(int i=0;i<=Max;++i){ if(i&(i>>1)||i&(i>>2)) continue; s[++cnt]=i; w[cnt]=getlen(i); if(!(state[1]&i)) f[1][cnt][1]=w[cnt]; } for(int i=1;i<=cnt;++i) for(int j=1;j<=cnt;++j){ if(s[i]&s[j]||state[2]&s[i]||state[1]&s[j]) continue; f[2][i][j]=w[i]+w[j]; } for(int i=3;i<=n;++i) for(int j=1;j<=cnt;++j){ if(state[i]&s[j]) continue; for(int k=1;k<=cnt;++k){ int ans=0; if((state[i-1]&s[k])||(s[j]&s[k])) continue; for(int l=1;l<=cnt;++l){ if((state[i-2]&s[l])||(s[j]&s[l])||(s[k]&s[l])) continue; ans=std::max(ans,f[i-1][k][l]); } f[i][j][k]=ans+w[j]; } } for(int i=1;i<=cnt;++i) for(int j=1;j<=cnt;++j) Ans=std::max(Ans,f[n][i][j]); printf("%d",Ans); return 0; }