题意:
思路:状压DP经典题
可以预处理下每一行内合法的状态,发现很少
所以转移时可以使用状态的编号而不是状态本身
DP时记录前两行状态的编号进行转移和判断
1 #include<cstdio> 2 #include<cstdlib> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstring> 6 #include<map> 7 #include<set> 8 #include<vector> 9 #define INF 10000 10 #define MAXK 65 11 using namespace std; 12 int dp[110][MAXK][MAXK]; 13 int a[MAXK],num[MAXK]; 14 int b[110]; 15 int n,m,K; 16 char s[12]; 17 18 int main() 19 { 20 freopen("poj1185.in","r",stdin); 21 freopen("poj1185.out","w",stdout); 22 scanf("%d%d",&n,&m); 23 for(int i=1;i<=n;i++) 24 { 25 scanf("%s",s+1); 26 for(int j=1;j<=m;j++) 27 if(s[j]=='H') b[i]+=(1<<(j-1)); 28 } 29 int MAX=(1<<m)-1; 30 for(int i=0;i<=MAX;i++) 31 if((!(i&(i<<1)))&&(!(i&(i<<2)))) 32 { 33 a[++K]=i; 34 num[K]=0; 35 int x=i; 36 while(x>0) 37 { 38 num[K]+=(x%2); 39 x>>=1; 40 } 41 } 42 43 for(int i=1;i<=n;i++) 44 for(int j=1;j<=K;j++) 45 for(int k=1;k<=K;k++) dp[i][j][k]=-INF; 46 47 for(int i=1;i<=K;i++) 48 if(!(b[1]&a[i])) dp[1][i][1]=num[i]; 49 50 for(int i=2;i<=n;i++) 51 for(int j=1;j<=K;j++) 52 if(!(b[i]&a[j])) 53 { 54 for(int k=1;k<=K;k++) 55 if(!(a[j]&a[k])) 56 { 57 for(int l=1;l<=K;l++) 58 { 59 if((a[l]&a[k])||(a[l]&a[j])) continue; 60 if(dp[i-1][k][l]==-INF) continue; 61 dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]); 62 } 63 } 64 } 65 66 int ans=0; 67 for(int i=1;i<=K;i++) 68 for(int j=1;j<=K;j++) ans=max(ans,dp[n][i][j]); 69 printf("%d ",ans); 70 return 0; 71 }