POJ 2411 Mondriaan's Dream

题意:用1*2的瓷砖拼出m*n的矩形。问有多少种拼法。

解法:设d[i][j]表示第i行状态为j的情况下,最多能有多少种拼法,对于状态j,1表示为竖着放置的瓷砖且它横跨i和i+1两行,其余皆用0表示。d[i][j] += d[i-1][k],其中k表示能转移到j的状态。

tag:状压dp

 1 /*
 2  * Author:  Plumrain
 3  * Created Time:  2013-11-19 01:01
 4  * File Name: DP-POJ-2411.cpp
 5  */
 6 #include <iostream>
 7 #include <cstdio>
 8 #include <cstring>
 9 #include <vector>
10 
11 using namespace std;
12 
13 #define CLR(x) memset(x, 0, sizeof(x))
14 #define PB push_back
15 typedef long long int64;
16 
17 int n, m;
18 int64 d[20][1<<12];
19 vector<int> pat[1<<12];
20 
21 bool gao1(int sta)
22 {
23     int x = 0, time = 0;
24     while (sta > 0){
25         x = sta & 1;
26         sta >>= 1;
27         if (!x){
28             if (time & 1) return 0;
29             time = 0;
30         }
31         else ++ time;
32     }
33     return !(time & 1);
34 }
35 
36 bool gao2(int s1, int s2)
37 {
38     for (int i = 0; i < m; ++ i){
39         int t1 = s1 & (1<<i), t2 = s2 & (1<<i);
40         if (!t1 && !t2) return 0;
41 
42         if (!t1) s2 ^= (1 << i);
43     }
44     return gao1(s2);
45 }
46 
47 void init()
48 {
49     for (int i = 0; i < (1<<m); ++ i)
50         pat[i].clear();
51     for (int i = 0; i < (1<<m); ++ i)
52         for (int j = 0; j < (1<<m); ++ j)
53             if (gao2(j, i)) pat[i].PB(j);
54 }
55 
56 int64 DP()
57 {
58     CLR (d);
59     for (int i = 0; i < (1<<m); ++ i)
60         d[0][i] = gao1(i);
61 
62     for (int i = 1; i < n; ++ i)
63         for (int j = 0; j < (1<<m); ++ j){
64             d[i][j] = 0;
65             for (int k = 0; k < (int)pat[j].size(); ++ k)
66                 d[i][j] += d[i-1][pat[j][k]]; 
67         }
68 
69     return d[n-1][(1<<m)-1];
70 }
71 
72 int main()
73 {
74     while (scanf ("%d%d", &n, &m) != EOF && n){
75         init();
76         printf ("%lld\n", DP());
77     }
78     return 0;
79 }
View Code

 

posted @ 2013-11-23 00:31  Plumrain  阅读(210)  评论(0编辑  收藏  举报