【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; }