首页 > 其他 > 详细

poj3254二进制放牛——状态压缩DP

时间:2018-02-23 00:43:05      阅读:243      评论:0      收藏:0      [点我收藏+]

题目: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

原文:https://www.cnblogs.com/Zinn/p/8460622.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!