POJ 3254 Corn Fields 状态压缩(dp)

链接:http://poj.org/problem?id=3254

Corn Fields
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 18865   Accepted: 9912

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

Line 1: Two space-separated integers:  M and  N 
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

Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.

Sample Input

2 3
1 1 1
0 1 0

Sample Output

9

Hint

Number the squares as follows:
1 2 3
  4  

There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.

Source

扫描二维码关注公众号,回复: 2625953 查看本文章

动态规划方程:

dp[i][state] +=dp[i-1][pre_state];

dp[i][state]的含义:第i行,状态为state所表示的二进制的方法数;所以dp[i][state] 应该等于上一行的所有可以和state存在的(就是上下两行是没有相邻)pre_state的和;

理解: 状压dp的核心就是用二进制表示某个状态,然后通过二进制的位操作来对这个状态进行操作;

判断上下不相邻:state&pre_state == 0   ;

判断左右不相邻:state&(state<<1) == 0 ;

代码如下:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m;
const int maxn = 13;
const int mod = 1e8;
int dp[maxn][1<<maxn]; 
int fertile[maxn][maxn];   //用于记录土地的情况 
long long ans = 0;

bool judge(int r,int state ){   //judge()的作用是判断 选择的state可不可以使用 
 	if(state & (state<<1))   // 判断state 是否存在左右相邻 
 		return false;
 	for(int i = 1;i <= m;i++){
 		if(!fertile[r][i])    //第r行 第i列 不能种植玉米 
 			if(((1<<(m-i))&state)>0)   //state所表示的状态 要在第r行第i列种植玉米 
 				return false;
	 }
	return true;  //返回true,表明state可以存在(这里还没有判断是否上下相邻 在main中判断) 
}

int main(){
	memset(dp,0,sizeof dp);
	cin>>n>>m;
	for(int i = 1; i <= n;i++)
		for(int j = 1;j <= m;j++){
			cin>>fertile[i][j];
		}

	for(int i = 1; i <= n;i++)
		for(int j = 0; j <  (1<<m) ;j++){
			if(judge(i,j)){  //如果state可以存在 
				if(i == 1)   
					dp[i][j] = 1;//如果是第一行土地,state的二进制所表示的状态初始值为 1 
				else
					for(int k = 0; k < (1<<m);k++){
						if(!(k&j))//k是上一行土地的状态,此处来判断是否上下相邻 
							dp[i][j] =(dp[i][j] + dp[i-1][k])%mod; //将上一行满足和state共存的dp[i][k]相加 
					}
			}
			if(i == n)
				ans = (ans+dp[i][j])%mod;//最后一行 i == n时所有的状态就是土地可以存在的所有状态个数 
		}
		cout<<ans<<endl;
		return 0;
}

猜你喜欢

转载自blog.csdn.net/curtern/article/details/80462720