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 }