洛谷p1879/poj3254 Corn Fields

看到这个题,又看了看数据规模,立马明白是一道状态压缩dp。

用 f [ i ][ j ] 表示第 i 行的状态为 j 时,前 i 行的方案总数 ( 状态用二进制表示,1表示放奶牛,0表示不放 ) 。

用 ok[ i ] 表示状态为 i 时是否合法,用 m[ i ]来储存第 i 行的肥沃土地。

预处理出每一行的合法状态(即没有两个格子相邻),然后以 每行 为阶段进行转移即可。

具体在转移时,除了考虑之前 ok 数组所记录的状态是否合法,还需要考虑:

1.与上一行是否冲突((j & k) == 0)

2.当前行的奶牛的位置上是否都有草((m[i] | j) == m[i])

那么不难写出代码。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int mod = 1e8;
 4 const int MAXN = 12 + 1;
 5 
 6 inline int read()
 7 {
 8     static int x;
 9     scanf(" %d", &x);
10     return x;
11 }
12 
13 int M, N;
14 bool ok[1 << 13];
15 int f[13][1 << 13], m[MAXN];
16 
17 int main()
18 {
19     cin>>M>>N;
20 
21     for(int i = 1; i <= M; i++)
22         for(int j = 0; j < N; j++)
23             m[i] |= (read() << j);
24 
25     bool flag;
26     for(int i = 0; i < (1 << N); i++)
27     {
28         flag = false;
29         for(int j = 1; j < 13; j++)
30             if( ((i >> j) & 1) & ( (i >> (j - 1)) & 1) ) flag = true;
31         ok[i] = (flag == false);
32     }
33 
34     f[0][0] = 1;
35     for(int i = 1; i <= M; i++)
36         for(int j = 0; j < (1 << N); j++)
37         {
38             if(ok[j] && ((m[i] | j) == m[i]))
39                 for(int k = 0; k < (1 << N); k++)
40                     if((j & k) == 0)
41                         f[i][j] = (f[i - 1][k] + f[i][j]) % mod;
42         }
43 
44     int ans = 0;
45     for(int i = 0; i < (1 << N); i++)
46         ans = (ans + f[M][i]) % mod;
47     cout<<ans<<endl;
48     return 0;
49 }
原文地址:https://www.cnblogs.com/wsmrxc/p/9031891.html