码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 1252-Twenty Questions(状态压缩DP+子集枚举)

时间:2015-03-11 09:24:10      阅读:106      评论:0      收藏:0      [点我收藏+]

标签:uva   dp   

题目大意:有n个物品,每个物品有m个特征,每个物品的每个特征都可能有或没有,现在假定某个物品,通过询问某些特征来确定这个物品,问最多需要多少次就可以确定物品。


每次询问之后可能根据答案不同来采取不同的进一步询问的策略。

用d[S][S0]表示目前询问了S,得到的回答是S0(即那个物品在S中有S0这些特征),最少还需询问多少次。枚举下一次询问的特征完成递推。最终d[0][0]就是答案。S0显然是S的一个子集。下一次询问的特征不是S已有的特征。如果对于某个d[S][S0]只有一个物品满足,那么此时值为0,不需要更多的询问。


状态转移方程:

d[S][S0]=min { max(d[S|u][S0],d[S|u][S0|u]) }(u==(1<<k),S&u==0)


#include<stdio.h>
#include<stdlib.h>
int a[150];
int d[2100][2100];
char e[1010];
int main(void)
{
	int i,j,u,p,q,n,m,sump,minp,OK,S,S0;
	scanf("%d%d",&m,&n);
	while((m!=0)||(n!=0))
	{
		for(i=1;i<=n;i++)
		{
			scanf("%s",e+1);
			sump=0;
			for(j=1;j<=m;j++)
			{
				sump=2*sump+e[j]-'0';
			}
			a[i]=sump;
		}
		p=(1<<m)-1;
		for(S=p;S>=0;S--)
		{
			S0=S;
			while(1)
			{
				sump=0;
				OK=1;
				for(i=1;i<=n;i++)
				{
					if((a[i]&S)==S0)
					{
						sump++;
						if(sump>1)
						{
							OK=0;
							break;
						}
					}
				}
				if(OK==1)
				{
					d[S][S0]=0;
				}
				else
				{
					minp=(1<<10);
					for(i=1;i<=m;i++)
					{
						u=1<<(i-1);
						if((u&S)==0)
						{
							q=d[S|u][S0]>d[S|u][S0|u]?d[S|u][S0]:d[S|u][S0|u];
							minp=q<minp?q:minp;
						}
					}
					d[S][S0]=minp+1;
				}
				if(S0==0)
				{
					break;
				}
				S0=(S0-1)&S;
			}
		}
		printf("%d\n",d[0][0]);
		scanf("%d%d",&m,&n);
	}
	return 0;
}


UVA 1252-Twenty Questions(状态压缩DP+子集枚举)

标签:uva   dp   

原文地址:http://blog.csdn.net/dilemma729/article/details/44187989

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!