POJ - 3254 Corn Fields

题目:
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.

代码如下:

#include<iostream>
#include<cstdio> 
using namespace std;
#define mod 100000000
int n,m;//图的行列 
int state[1000];//保存第一行所有可能的情况
int top;//可能的种类 
int dp[13][1000];//dp[i][j]表示前i行,且第i行状态为j时的方案个数 
int cur[12];//cur[i]表示第i行现在的状态 
bool ok(int i)
{
	if(i & i << 1) return false;//防止出现左右相邻的状态 
	return true; 
}
void init()
{
	top = 0;
	int num = 1 << n;//一列中所有情况数 
	for(int i = 0;i < num;i++) if(ok(i)) state[top++] = i; 
}
bool fit(int i,int m){	//判断状态i是否和第k行现在的状态是否有重合 
	if(i & cur[m]) return false;
	return true;
} 
int main()
{
	int num,ans = 0;
	while(~scanf("%d%d",&m,&n)){
		init();//将第一行所有的可能都保存下来 
		for(int i = 1;i <= m;i++){
			cur[i] = 0;
			for(int j = 1;j <= n;j++){
				cin >> num; 
				if(!num) cur[i] += (1 << (n - j));//第i行第j列不能放牛,所以将第i行第j列填为1 
			} 	
		} 
		for(int i = 0;i < top;i++)
			if(fit(state[i],1)) 
				dp[1][i] = 1;//如果第一行的状态state[i]是可行的,那就说明这算是一种方案数 
		for(int i = 2;i <= m;i++){
			for(int j = 0;j < top;j++){
				if(!fit(state[j],i)) continue;//第j种状态要是和第i行状态重合就跳过 
				for(int k = 0;k < top;k++){
					if(!fit(state[k],i - 1)) continue;//第k种状态要是和第i - 1行状态重合就跳过 
					if(state[j] & state[k]) continue;//把2行种同一列都存在1的情况删去 
					dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod; 
				}
			}
		} 
		for(int i = 0;i < top;i++) ans = (ans + dp[m][i]) % mod;//把所有的可能的累加起来 
		cout << ans << endl; 
	}
	return 0;
}

今天刚刚学了状压dp,就挑了这道入门题来做。
题意:给你m行n列,1代表能放牛,0代表不能放。放牛要是的同一行之间不能使两头牛相邻,同一列也是。

思路:这道题如果使用搜索复杂度太高肯定算1天都算不完,这里使用状压dp,可以使复杂度降低。这里每一行用二进制来表示,1表示放了牛,0表示没放,每一种状态看成二进制数,转换为10进制之后每一个值都是不一样的。具体过程上述代码写有我的理解,感觉要学会状压dp首先要熟悉使用位运算符。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值