http://poj.org/problem?id=2411
题意:给定N*M的棋盘,放置1*2的小矩形,问一共有多少种不同的摆放方法。
好文章:
http://www.cppblog.com/sdfond/archive/2009/07/31/91761.html
PS:周伟的论文《状态压缩》论文里,有点错。
留着代码以后看:
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #define MAX_ROW 11 #define MAX_S 2048 #define LL long long using namespace std; LL dp[MAX_ROW][MAX_S]; int n,m; bool testline(int nS) { int i=0; while (i<m) { if (nS&(1 <<i)) { if (i==m-1 || (nS &(1<<(i+1)))==0) { return false; } i+=2; } else i++; } return true; } bool comp(int nA,int nB) { int i=0; while (i<m) { if ((nA&(1<<i))==0) { if ((nB&(1<<i))==0) return false; i++; }else{ if ((nB & (1<<i))==0) { i++; } else if (i==m-1 || !((nA&(1<<(i+1))) && (nB&(1<<(i+1))))) { return false; }else{ i+=2; } } } return true; } int main() { int i,j; int k; while (scanf("%d%d",&n,&m)!=EOF) { if (n==0 && m==0) break; if (m>n) { int tmp = m; m = n; n = tmp; } int tot = 2<<(m-1); memset(dp,0,sizeof(dp)); for (j=0;j<tot;j++) if (testline(j)) dp[0][j]=1; for (i=1;i<n;i++) { for (j=0;j<tot;j++) { for (k=0;k<tot;k++) if (comp(j,k)) dp[i][j]+=dp[i-1][k]; } } printf("%lld\n",dp[n-1][tot-1]); } return 0; }
使用dfs写了一个,效率大增啊!
#include<stdio.h> #include<string.h> #include<math.h> #define LL long long int n,m; int deep; LL dp[14][2050]; void dfs(int p,int s1,int s2,int b1,int b2){ if (p==m){ if (b1 == 0 && b2==0){ // printf("%d %d %d\n",s1,s2,b2); dp[deep+1][s2] += dp[deep][s1]; } return ; } if (b2 == 0){ if (b1 == 0){ dfs(p+1,(s1<<1),(s2<<1)+1,0,0); //1 0 //1 0 } dfs(p+1,(s1<<1)+1,(s2<<1)+1,0,1); //0 0 //1 1 } dfs(p+1,(s1<<1)+1,(s2<<1)+b2,0,0); //0 0 //0 0 return ; } int main() { while (scanf("%d%d",&n,&m)==2){ if (n == 0 && m==0) break; if (n%2==1 &&m%2==1){ printf("0\n"); continue; } if (n < m){ int tmp = n; n = m; m = tmp; } memset(dp,0,sizeof(dp)); dp[0][(1<<m)-1] = 1; for (deep=0;deep<n;deep++){ dfs(0,0,0,0,0); } printf("%I64d\n",dp[n][(1<<m)-1]); } return 0; }