poj 2411 状态压缩dp
思路:将每一行看做一个二进制位,那么所有的合法状态为相邻为1的个数一定要为偶数个。这样就可以先把所有的合法状态找到。由于没一层的合法状态都是一样的,那么可以用一个数组保存。由第i-1行到第i行的状态转移是dp[i][now|num[j]]+=dp[i-1][k],其中now为(1<<m)-1-k;也就是把k中含有0的变1,1边0。k为第i-1行的所有二进制状态,转移条件是k&num[j]==num[j]。唯一注意的是,最后一行的条件是k^num[j]==0.
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define Maxn 13 #define inf 0x7fffffff using namespace std; __int64 dp[Maxn][1<<Maxn]; int num[1<<Maxn],cnt1,cnt2,graphic[Maxn],co,n,m; void dfs(int j,int f) { int i; if(j==m) { int sum=0; if(f) graphic[j]=1; else graphic[j]=0; for(i=m;i>=1;i--) sum+=graphic[i]*(1<<(m-i)); num[++cnt2]=sum; return ; } if(!f) { graphic[j]=0; dfs(j+1,0); graphic[j]=1; dfs(j+1,1); } else { graphic[j]=1; dfs(j+1,0); } } int main() { int i,j,k; while(scanf("%d%d",&n,&m)!=EOF,n||m) { if((n*m)%2) { printf("0\n"); continue; } if(n==1) { printf("1\n"); continue; } memset(dp,0,sizeof(dp)); graphic[0]=0; cnt2=0; dfs(1,0); for(i=1;i<=cnt2;i++) dp[1][num[i]]=1; int temp=1<<m; temp--; for(i=2;i<=n-1;i++) { for(j=1;j<=cnt2;j++) { for(k=0;k<=temp;k++) { if((k&num[j])==num[j]) { int now=temp-k; dp[i][now|num[j]]+=dp[i-1][k]; } } } } __int64 ans=0; for(j=1;j<=cnt2;j++) { for(k=0;k<=temp;k++) { if((k^num[j])==0) ans+=dp[i-1][k]; } } printf("%I64d\n",ans); } return 0; }