BZOJ 1725 Corn Fields

状压DP
DP[i][j]表示已放完i行,第i行放置状态为j的方案数
预处理出所有满足一行中无两格相邻的放置方案
列数为12时这个方案数少于400
枚举方案转移,需要满足与上一行无交且是Map(可行格)的子集

#include <cstdio>

const int MAXN=12;
const int MAXM=12;
const int MOD=100000000;

int N, M, Val;
int Map[MAXN];
int DP[MAXN][1<<MAXM];

bool Test(int a){
	bool ret=true;
	for(int i=0, p=0;i<M;++i, a>>=1){
		if(p>0 && (a&1))	{ret=false;break;}
		p=a&1;
	}
	return ret;
}

int Put[1<<MAXM], Pcnt;

int main(){
	
	scanf("%d%d", &N, &M);
	for(int i=0;i<N;++i){
		Map[i]=0;
		for(int j=0, a;j<M;++j){
			scanf("%d", &a);
			if(a>0)	Map[i]+=(1<<j);
		}
	}
	
	for(int i=(1<<M)-1;i>=0;--i)
		if(Test(i))
			Put[++Pcnt]=i;
	
	//for(int i=1;i<=Pcnt;++i)
	//	printf("%d\n", Put[i]);
	
	for(int i=1;i<=Pcnt;++i){
		if((Put[i]&Map[0])==Put[i]){
			DP[0][Put[i]]=1;
		}
	}
	
	for(int i=0;i+1<N;++i){
		for(int j=(1<<M)-1;j>=0;--j){
			if(DP[i][j]<=0)	continue;
			for(int p=1;p<=Pcnt;++p){
				if((Put[p]&Map[i+1])==Put[p] && (Put[p]&j)==0){
					DP[i+1][Put[p]]+=DP[i][j];
					if(DP[i+1][Put[p]]>=MOD)	DP[i+1][Put[p]]-=MOD;
				}
			}
		}
	}
	
	int Ans=0;
	for(int j=(1<<M)-1;j>=0;--j){
		Ans+=DP[N-1][j];
		if(Ans>=MOD)	Ans-=MOD;
	}
	printf("%d\n", Ans);
	
	return 0;
}

posted @ 2018-09-11 16:39  Pickupwin  阅读(113)  评论(0编辑  收藏  举报