bzoj 1725:Corn Fields牧场的安排

Description

Farmer John新买了一块长方形的牧场,这块牧场被划分成M列N行(1<=M<=12; 1<=N<=12),每一格都是一块正方形的土地。FJ打算在牧场上的某几格土地里种上美味的草,供他的奶牛们享用。遗憾的是,有些土地相当的贫瘠,不能用来放牧。并且,奶牛们喜欢独占一块草地的感觉,于是FJ不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。当然,FJ还没有决定在哪些土地上种草。 作为一个好奇的农场主,FJ想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择。当然,把新的牧场荒废,不在任何土地上种草,也算一种方案。请你帮FJ算一下这个总方案数。

Input

* 第1行: 两个正整数M和N,用空格隔开

* 第2..M+1行: 每行包含N个用空格隔开的整数,描述了每块土地的状态。输入的第i+1行描述了第i行的土地。所有整数均为0或1,是1的话,表示这块土地足够肥沃,0则表示这块地上不适合种草

Output

* 第1行: 输出一个整数,即牧场分配总方案数除以100,000,000的余数


          感觉这是一道简单版的炮兵阵地?

      很容易想到这道题的状态为dp[i][state]表示考虑到第i行了,state中的0或1表示选或没选。

      接下来考虑转移,对于现在这一行的每个状态,肯定是由上一行的某个与它互相不干涉的状态转移而来,

      为了判断上下互相不干涉,我们只需要两个相与值为0即可判断,

      对于左右无相邻,我们可以讲当前state左移一位与当前state相与,如果为0,则说明没有相邻选中的了。

      对于不在贫瘠的草上,我们可以将贫瘠的草设为1,将当前状态与草地状态相与,如果为0,则说明没有选中的在贫瘠的草上了。

      最后考虑边界条件,对于开始,第0行全不选的答案为1,很套路的状态了。最终的答案便是,最后一行,所有状态的答案之和。

       下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#define maxn 14
using namespace std;
typedef long long ll;
const ll mod=100000000;
ll n,m;
ll dic[maxn];
ll dp[maxn][(1<<maxn)];
ll judge1(ll now)
{
	if((now&(now>>1))) return false;
	return true;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	
	for(ll i=0;i<n;i++)
	for(ll j=0;j<m;j++)
	{
		ll x;
		scanf("%lld",&x);
		if(x==0)
		dic[i]|=(1<<j);
	}
	
	dp[0][0]=1;
	
	for(ll i=0;i<n;i++)
	{
		for(ll state=0;state<(1<<m);state++)
		{
			for(ll nex=0;nex<(1<<m);nex++)
			{
				if(judge1(nex) && (state&nex)==0 && (nex&dic[i])==0)
				{
					dp[i+1][nex]+=dp[i][state];
					if(dp[i+1][nex]>=mod)
					dp[i+1][nex]-=mod;
				} 
			}
		}
	}
	
	ll ans=0;
	for(ll state=0;state<(1<<m);state++)
	{
		ans+=dp[n][state];
		if(ans>mod)
		ans-=mod;
	}
	printf("%lld\n",ans);
}


     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值