1. 程式人生 > >poj3254二進制放牛——狀態壓縮DP

poj3254二進制放牛——狀態壓縮DP

true 上界 pos csharp targe pac 狀態 二進制 arp

題目:http://poj.org/problem?id=3254

利用二進制壓縮狀態,每一個整數代表一行的01情況;

註意預處理出二進制表示下沒有兩個1相鄰的數的方法,我的方法(不知為何)錯了,看到了別人的優美方法;

再進行DP即可。

代碼如下:

#include<iostream>
#include<cstdio>
using namespace std;
int m,n,a[15],num[15],p[3005],f[15][3005],tot,INF=100000000,ans;
//int pw(int w)
//{
//	int ret=1;
//	int sum=1;
//	while(w)
//	{
//		ret*=2;
//		if(w&1)sum*=ret;
//		w/=2;
//	}
//	return sum;
//}
//void ap(int w,int b,int jl)//2^w  b=0/1  +jl
//{
//	if(w==n-1)
//	{
//		if(!b)p[++tot]=jl;
//		else
//		{
//			p[++tot]=jl;
//			p[++tot]=jl+pw(w);
//		}
//		return;
//	}
//	if(!b)ap(w+1,1,jl);
//	else
//	{
//		ap(w+1,0,jl+pw(w));
//		ap(w+1,1,jl);
//	}
//}
inline bool ok(int x){  //判斷狀態x是否可行  
   if(x&x<<1) return false;//若存在相鄰兩個格子都為1,則該狀態不可行  
   return true;  
}  
void init(){            //遍歷所有可能的狀態  
   int total = 1 << n; //遍歷狀態的上界  
   for(int i = 0; i < total; ++i){  
       if(ok(i))p[++tot] = i;     
   }  
}  
int main()
{
	scanf("%d%d",&m,&n);
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
		{
			scanf("%d",&a[j]);
			num[i]*=2;
			num[i]+=a[j];
		}
	init();
//	ap(0,1,0);
//	cout<<tot<<endl;
	for(int i=1;i<=tot;i++)
	{
//		cout<<p[i]<<endl;
		if(!(p[i]&(~num[1])))f[1][i]++;
	}
	for(int i=2;i<=m;i++)
	{
		for(int j=1;j<=tot;j++)
		{
			if(p[j]&(~num[i-1]))continue;
			for(int k=1;k<=tot;k++)
			{
				if((p[k]&(~num[i]))||(p[k]&p[j]))continue;
				f[i][k]+=f[i-1][j];
				f[i][k]%=INF;
			}
		}
	}
	for(int i=1;i<=tot;i++)
	{
		ans+=f[m][i];
		ans%=INF;
	}
	printf("%d",ans);
	return 0;
}

  

poj3254二進制放牛——狀態壓縮DP