POJ 2411 Mondriaan's Dream(状态压缩DP)
早就见过这个题,开始以为有公式的,推了几次没推出,后来知道这个题是状态压缩DP。最近开始看状态压缩,本想试着解出来,但是这个比那个牛吃草复杂多了。。。位运算还是不是很熟练,这个题的解题报告有很多方法,最重要的就是状态转移,基本上都是用DFS写的,我看的做法是DISCUSS里的做法。用1表示横放,0表示竖放。然后转移的时候吧上一行的状态取反(~j&((1<<m)-1),然后去DFS就行了,注意是在(~j&((1<<m)-1)这个数字的二进制基础上进行DFS,加入横放或者竖放。结束的状态就是矩阵的所有的元素都是1.
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 #define ll __int64 6 ll dp[13][1<<12]; 7 ll tem; 8 int n,m; 9 void dfs(int i,int k,int pos)//搜索 10 { 11 if(pos == m) 12 { 13 dp[i][k] += tem; 14 return ; 15 } 16 dfs(i,k,pos+1);//竖放 17 if(pos<=m-2&&!(k&1<<pos)&&!(k&1<<pos+1))//是否可以横放,判断pos和pos+1是否都是0 18 { 19 dfs(i,k|1<<pos|1<<pos+1,pos+2);//让这两个位置为1 20 } 21 } 22 int main() 23 { 24 int i,j; 25 while(scanf("%d%d",&n,&m)!=EOF) 26 { 27 memset(dp,0,sizeof(dp)); 28 if(!n&&!m) break; 29 if((n*m)%2) 30 { 31 printf("0\n"); 32 continue; 33 } 34 tem = 1; 35 dfs(1,0,0); 36 for(i = 2;i <= n;i ++) 37 { 38 for(j = 0;j < 1<<m;j ++) 39 { 40 if(dp[i-1][j]) 41 tem = dp[i-1][j]; 42 else 43 continue; 44 dfs(i,~j&((1<<m)-1),0); 45 } 46 } 47 //for(i = 0;i < 1<<m;i ++) 48 //printf("%I64d ",dp[n][i]); 49 printf("%I64d\n",dp[n][(1<<m)-1]); 50 } 51 return 0; 52 }