【poj3254】Corn Fields 状态压缩dp

AC通道:http://vjudge.net/problem/POJ-3254

【题目大意】

农夫约翰购买了一处肥沃的矩形牧场,分成M*N(1<=M<=12; 1<=N<=12)个格子。他想在那里的一些格子中种植美味的玉米。遗憾的是,有些格子区域的土地是贫瘠的,不能耕种。

精明的约翰知道奶牛们进食时不喜欢和别的牛相邻,所以一旦在一个格子中种植玉米,那么他就不会在相邻的格子中种植,即没有两个被选中的格子拥有公共边。他还没有最终确定哪些格子要选择种植玉米。

作为一个思想开明的人,农夫约翰希望考虑所有可行的选择格子种植方案。由于太开明,他还考虑一个格子都不选择的种植方案!请帮助农夫约翰确定种植方案总数。

【题解】

这是一道很基础的题,先预处理出合法的状态,然后枚举这些状态,然后按行实现转移。

不懂的看我代码。

/*************
  poj 3254
  by chty
  2016.11.15
*************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define mod 100000000
#define FILE "read"
#define up(i,j,n) for(ll i=j;i<=n;i++)
namespace INIT{
	char buf[1<<15],*fs,*ft;
	inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
	inline ll read(){
		ll x=0,f=1;  char ch=getc();
		while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
		while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
		return x*f;
	}
}using namespace INIT;
ll n,m,ans,cnt,vst[1<<12],map[15][15],f[15][1<<12];
void pre()  {up(i,0,(1<<m)-1)  if((i&(i<<1))==0)  vst[++cnt]=i;}//预处理出合法的状态
bool check(ll x,ll y)  {ll temp=0; up(i,1,m) if(map[x][i]) temp+=(1<<(m-i)); return (!(y&(~temp)));}//检验当前状态是否合法
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	n=read();  m=read();
	up(i,1,n)  up(j,1,m)  map[i][j]=read();
	pre();  f[0][0]=1;
	up(i,1,n) up(j,1,cnt) if(check(i,vst[j])){
		up(k,1,cnt) if(check(i-1,vst[k])&&(!(vst[k]&vst[j])))  
			f[i][vst[j]]+=f[i-1][vst[k]];
	}
	up(i,1,cnt)  ans+=f[n][vst[i]];
	printf("%lld\n",ans%mod);
	return 0;
}


posted @ 2016-11-15 21:12  chty  阅读(166)  评论(0编辑  收藏  举报