UVA 1252-Twenty Questions(状态压缩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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值