POJ 3254 Corn Fields(状态压缩DP入门)
Posted wangrunhu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3254 Corn Fields(状态压缩DP入门)相关的知识,希望对你有一定的参考价值。
Description
Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can‘t be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.
Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.
Input
Lines 2..M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)
Output
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
思路:题目大意是农夫有一块地,被划分成一个n*m的放个区域,每个区域有一个数字0或1,1代表可以放牛,0代表不可以. 每一个位置可以放牛的条件是上下左右相邻位置都没有放牛;现在给定一个n*m的序列问你农夫放牛的情况有多少种?
解题:将每一行的01序列(也就是放牛的状态)看成是二进制数将之转换成十进制数存起来,我们就将这个二维的问题转换成了一位,每一次只需要对每一行进行判断即可。
以样例第一行为例子,有0,0,0; 0,1,0; 1,0,0; 0,0,1; 1,0,1;这五种可能放牛的情况,我们可以将这每一行的01序列成一个二进制序列将之转化成一个10进制数就为0,2,1,4,5;这样一个十进制数就可以表示每一行可以放牧的状态;
而第二行则有0,0,0; 0,1,0;而这一行的每一种情况还要考虑跟上一行有没有相邻的情况,0,0,0与上一行的五种都无相邻,而0,1,0与上一行0,1,0相邻所以只有四种 所以答案是5+4 = 9;
emmm。。。为也是初学 可能很多地方讲的比较模糊,望见谅
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 const int mod = 1e9; 7 const int N = 13; 8 int pass[1 << N], now[1 << N];//存储可以每一列可以放牧的种类数,mp代表每一行的不可以放牧的状态 9 int dp[N][1 << N];//dp[i][j] 代表第i行按第j种放牧情况的种类数 10 int n, m; 11 bool check(int x) { 12 return (x&(x << 1));//判断一行是否有相邻放牧的情况 13 } 14 bool judge(int x, int y) { 15 return (now[x] & pass[y]);//判断当前第x行不可以放牧状态x和可以放牧状态y的交集 16 //也就是如果在不可以放牧的位置上有放牧的这一可能就返回真(即不可以放牧)否则这一种放牧情况y就可以 17 } 18 int main() 19 { 20 ios::sync_with_stdio(false); 21 while (cin >> n >> m) { 22 memset(pass, 0, sizeof(pass)); 23 memset(now, 0, sizeof(now)); 24 memset(dp, 0, sizeof(dp)); 25 for (int i = 1; i <= n; i++) 26 for (int x,j = 1; j <= m; j++) { 27 cin >> x; 28 if (x == 0) 29 now[i] += (1 << (j - 1));//将不可放牧的状态存入数组,将每一行01序列转换成10进制数 30 } 31 int cnt = 0; 32 for (int i = 0; i < (1 << m); i++)//因为有m列所以每一行的状态有2^m种 0为不放牧的情况 33 if (!check(i))//每一种状态都不存在相邻的放牧位置的时候即为合法状态 34 pass[cnt++] = i; 35 for (int i = 0; i < cnt; i++) 36 if (!judge(1, i))//如果当前的合法状态跟第一行的不可放牧状态没有交集的时候就代表可以放牧 37 dp[1][i] = 1;//因为是第一行所以种类数为1 38 for (int i = 2; i <= n; i++) { 39 for (int j = 0; j < cnt; j++) {//判断当前行的放牧状态 40 if (judge(i, j))continue;//如果当前第j种状态不可行 41 for (int k = 0; k < cnt; k++) {//判断上一行的放牧状态 42 if (judge(i - 1, k))continue; 43 if (!(pass[j] & pass[k])) {//如果当前行第j种状态可行并且和上一行第k种状态不冲突 44 dp[i][j] += dp[i - 1][k];//就加上上一行第k种状态的种数 45 dp[i][j] %= mod; 46 } 47 } 48 } 49 } 50 int ans = 0; 51 for (int i = 0; i < cnt; i++) 52 ans = (ans + dp[n][i]) % mod; 53 cout << ans << endl; 54 } 55 return 0; 56 }
以上是关于POJ 3254 Corn Fields(状态压缩DP入门)的主要内容,如果未能解决你的问题,请参考以下文章
[ An Ac a Day ^_^ ] POJ 3254 Corn Fields 状压dp