POJ3254Corn Fields(状态压缩DP入门)

题目链接

题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)

分析:每一行看做一个状态,用一个二进制数来表示,每一行会排出牛和牛相邻的情况;由上一行转移到下一行的条件就是这一行和上一行不会存在1在同一列,也就是与操作后为0,

状态表示: dp[state][i] 表示 在状态为state情况下第i行可以满足的方案数

状态转移:DP[state][i] += dp[state'][i - 1] (state & state' == 0)

状态压缩总结博客

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 const int Mod = 100000000;
 7 int state[600];
 8 int dp[20][600], cur[20];
 9 int n, m, total, top;
10 inline bool is_ok(int x)
11 {
12     if (x & (x << 1)) // 如果存在相邻的1返回0
13         return 0;
14     return 1;
15 }
16 void init()
17 {
18     top = 0;
19     total = 1 << n;
20     for (int i = 0; i < total; i++)  
21         if(is_ok(i))
22             state[++top] = i;
23 }
24 inline bool fit(int x, int i)
25 {
26     if (x & cur[i]) 
27         return 0;
28     return 1;
29 }
30 int main()
31 {
32     while (scanf("%d%d", &m, &n) != EOF)
33     {
34         init();
35         int num;
36         for(int i = 1; i <= m; i++)
37         {
38             cur[i] = 0;
39             for(int j = 1; j <= n; j++)
40             {
41                 scanf("%d", &num);
42                 if (num == 0)
43                     cur[i] += (1 << (n - j));
44 //这里之前不明白为什么num == 0的时候开始计数,把不允许放牧的地方都设为1,而允许放牧的就是0,所以判断当前状态与哪些标准状态匹配时候只需判断 & 之后是否为0,因为只要是非0,一定是不行的,在那一个点下不允许放牧,标准却可以放牧。 当前状态可以放牧,即为0,那么标准状态下,这一个位置放不放都可以,所以标准下0,1都可以
45             }
46         }
47         memset(dp, 0, sizeof(dp));
48         for (int i = 1; i <= top; i++)
49         {
50             if (fit(state[i], 1)) // 先判断第一行的情况,state[1] = 0,这也是可以的
51                 dp[1][i] = 1;
52         }
53 
54         for (int i = 2; i <= m; i++)
55         {
56             for(int k = 1; k <= top; k++) // 判断第 i 行可以由哪些标准状态
57             {
58                 if(!fit(state[k], i)) continue;
59                 for (int j = 1; j <= top; j++)  
60                 {
61                     if(!fit(state[j], i - 1)) continue; //选择i-1可以的标准状态
62                     if (state[k] & state[j]) continue; // 没有列相邻的1
63                     dp[i][k] += dp[i - 1][j];
64                     dp[i][k] %= Mod;
65                 }
66             }
67         }
68         int ans = 0;
69         for (int i = 1; i <= top; i++)
70         {
71             ans += dp[m][i];
72             ans %= Mod;
73         }
74         printf("%d\n", ans);
75     }
76     return 0;
77 }
View Code

 

posted @ 2016-03-26 12:17  zhaop  阅读(223)  评论(0编辑  收藏  举报