【状压基础题】poj3254 Corn Fields

 

 

 

题目大意 :农夫约翰有n*m块地,其中一些地荒掉了。玉米是一种傲娇的植物,种在相邻的地里会导致不孕不育。求所有种法数对100000000求余。

读入:第一行一个n一个m,

接下来是一个n行m列的矩形,表示田地的状态(1表示可种植,0表示不可种植)

输出:一个整数,表示总的方法数 % 1000000000的结果

首先我们把原图的每一行转成二进制数存储(此处及以下原图均指读入的田地状况),1表示可以种植,0表示不能种植
以行为阶段,对于每一行,我们把可以种的标记为1,不能种则标记为0
分析同一行中,我们由题目可以知道,两个1肯定不相邻,
我们想把当前状态左移1位再与原数相&,若结果不为0,则肯定有两个1相邻了
但是同样我们要注意的是,两行之间相邻也是不允许的
例如:
0001010
0001001
第一行第4个位置为1,下一行第4个位置仍为1,上下两个1相邻了,这样也是不允许的
这样我们设一个状态为k,由状态k转移到状态j,若j&k!=0,则出现了上下两个1相邻,这样是不符合的
接着我们必须符合原图,也就是原图中不能种的地方我们一定不能种,原图中不能种的地方为0,能种的地方为1
但是比较麻烦的是,原图能种的地方我们不一定种,原图不能种的地方,在我们的状态中可能种,我们没办法区分这两种情况
那么我们试着翻转一下操作
存原图时,我们用0表示能种,1表示不能种(最初我们用1表示能种,0表示不能种)
这样我们可以直接相&,若出现了1,则一定不能种。因为此时我们标记为1的位置,按照题目要求,在原图中一定要标记为0,如果某个位置我们种了而原图中
不能种,那么相&得到的就是1,这样是不行的。问题就解决了。
然后我们可以以非常显然的方式得到dp数组
f[i, j]表示在第i行(i为一个m位的二进制数),状态为j时,所有的种法,这样得到的状态转移方程就是:
f[i, j] = Σf[i - 1, k]( j & k == 0 && j & a[i] == 0 && k & a[i - 1] == 0)
初态:f[0, 0] = 1;
目标:Σ{f[n, i]}(i为m位二进制数,0 <= i < 1 << m)

 1 #include<iostream>
 2 #include<iomanip>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<ctime>
 6 #include<cstring>
 7 #include<algorithm>
 8 #include<cstdlib>
 9 #define ll long long
10 using namespace std;
11 const int mod = 100000000;
12 int n, m, h;
13 ll f[13][1 << 13], ans = 0;
14 ll a[13];
15 
16 inline int read() {
17     int  x = 0, y = 1;
18     char ch = getchar();
19     while(!isdigit(ch)) {
20         if(ch == '-') y = -1;
21         ch = getchar();
22     }
23     while(isdigit(ch)) {
24         x = (x << 1) + (x << 3) + ch - '0';
25         ch = getchar();
26     }
27     return x * y;
28 }
29 
30 int main() {
31     n = read(), m = read();
32     for(int i = 1; i <= n; ++i)
33         for(int j = 1; j <= m; ++j) {
34             h = read();
35             a[i] <<= 1;
36             a[i] += (h == 0) ? 1 : 0;
37         }
38     f[0][0] = 1;
39     for(int i = 1; i <= n; ++i) 
40         for(int j = 0; j < 1 << m; ++j) {
41             if(j & (j << 1) || j & a[i]) continue;
42             for(int k = 0; k < 1 << m; ++k) {
43                 if(j & k || k & a[i - 1] || k & (k << 1)) continue;
44                 f[i][j] = (f[i][j] + f[i - 1][k]) % mod;
45             }
46         }
47     for(int i = 0; i < 1 << m; ++i)
48         ans = (ans + f[n][i]) % mod;
49     cout << ans << '\n';
50     return 0;
51 } 

 

posted @ 2018-06-29 14:52  YuWenjue  阅读(190)  评论(0编辑  收藏  举报