状压的基础题吧
第一次看感觉难上天,后来嘛就。。
套路:先根据自身状态筛出可行状态,再根据地图等其他限制条件筛选适合的状态加入答案
f i,j,k 分别代表 行数,本行状态,上行状态,再累加答案即可
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} inline int calc(int x){int ans=0;for(;x;x-=x&(-x))ans++;return ans;} //state 状态的具体集合 //num 状态的答案贡献(1数量) int cnt,n,m; int f[100][64][64],num[64],state[64],g[100]; void dp(){ int ans=0; memset(f,0,sizeof f); for(int i=0;i<n;i++)//本行 for(int j=0;j<cnt;j++){//本行状态 if(g[i]&state[j]) continue; if(i==0) f[i][j][0]=num[j]; else if(i==1){ for(int k=0;k<cnt;k++){ if(g[i-1]&state[k]) continue; if(state[j]&state[k]) continue; f[i][j][k]=max(f[i][j][k],f[i-1][k][0]+num[j]); } }else{ for(int k=0;k<cnt;k++){ if(g[i-1]&state[k]) continue; if(state[j]&state[k]) continue; for(int p=0;p<cnt;p++){ if(g[i-2]&state[p]) continue; if(state[k]&state[p]||state[j]&state[p]) continue; //三行都要兼容 f[i][j][k]=max(f[i][j][k],f[i-1][k][p]+num[j]); } } } } for(int j=0;j<cnt;j++) for(int k=0;k<cnt;k++) ans=max(ans,f[n-1][j][k]); printf("%d\n",ans); } int main(){ char s[12]; int i,j; n=read();m=read(); for(i=0;i<n;i++){ scanf("%s",s); for(j=0;j<m;j++) if(s[j]=='H') g[i]+=(1<<(m-1-j)); } int tmp;cnt=0; for(int i=0;i<(1<<m);i++){ tmp=i; if(((tmp<<1)&i)|((tmp<<2)&i)) continue; state[cnt]=i; num[cnt]=calc(i);++cnt;} //利用函数计算当前状态中1的数量 //cnt代表当前限制条件下合法状态 dp();return 0; } //先根据自身条件确定状态 //再根据给定地图判断