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 }
posted @ 2012-09-27 19:11  Naix_x  阅读(166)  评论(0编辑  收藏  举报