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;
}
时间: 2024-10-12 15:31:43

UVA 1252-Twenty Questions(状态压缩DP+子集枚举)的相关文章

UVA 1252 Twenty Questions 状压DP

简单状压DP: 当前状态s如果这个物品有状态a个属性,枚举下一个要猜测的特征k dp[s][a]=min(dp[s][a],max(dp[s+k][a],dp[s+k][a+k])+1); 4643 - Twenty Questions Asia - Tokyo - 2009/2010 Consider a closed world and a set of features that are defined for all the objects in the world. Each feat

UVA - 1252 Twenty Questions (状压dp+vis数组加速)

有n个物品,每个物品有m个特征.随机选择一个物品让你去猜,你每次可以询问一个特征的答案,问在采取最优策略时,最坏情况下需要猜的次数是多少. 设siz[S]为满足特征性质集合S的特征的物品总数,dp[S]为当前得到的物品特征信息为S的情况下最坏情况下需要猜多少次,则$dp[S]=max\{dp(S|(1<<(2*i))),dp(S|(2<<(2*i))\}$(为了表示某个特征不确定的状态,需要将集合大小加倍).dfs预处理siz的复杂度为$O(n*2^m)$,dp的复杂度为$O(m*

UVa 1252 - Twenty Questions(记忆化搜索,状态压缩dp)

题目链接:uva 1252 题意: 有n个长度为m的二进制串,每个都是不同的. 为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1. 问最少提问次数,可以把所有字符串区分开来. 思路来源于:点击打开链接 思路: m很小,可以考虑状态压缩. dp[s1][s2]表示询问的状态为s1时,此时能猜到状态包含s2时最小需要的步数. 当询问的几位=s2的二进制串小于2时就能区分出来了,dp[s1][s2]=0: 不能区分则再询问一次,s1|=(1<<k),如果问某位为0,则s2不变,问某位为

状压DP+记忆化搜索 UVA 1252 Twenty Questions

题目传送门 1 /* 2 题意:给出一系列的01字符串,问最少要问几个问题(列)能把它们区分出来 3 状态DP+记忆化搜索:dp[s1][s2]表示问题集合为s1.答案对错集合为s2时,还要问几次才能区分出来 4 若和答案(自己拟定)相差小于等于1时,证说明已经能区分了,回溯.否则还要加问题再询问 5 */ 6 /************************************************ 7 * Author :Running_Time 8 * Created Time :

UVA 11825 状态压缩DP+子集思想

很明显的状态压缩思想了.把全集分组,枚举每个集合的子集,看一个子集是否能覆盖所有的点,若能,则f[s]=max(f[s],f[s^s0]+1).即与差集+1比较. 这种枚举集合的思想还是第一次遇到,果然太弱了....~~~~ 其中枚举集合 for(s0=s;s0;s0=(s0-1)&s) #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> usin

UVa 1252 - Twenty Questions(状压DP)

链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3693 题意: 有n(n≤128)个物体,m(m≤11)个特征.每个物体用一个m位01串表示,表示每个特征是具备还是不具备.我在心里想一个物体(一定是这n个物体之一),由你来猜.你每次可以询问一个特征,然后我会告诉你:我心里的物体是否具备这个特征.当你确定答案之后,就把答案告诉我(告

(状压dp)UVA - 1252 Twenty Questions

题目地址 读入二进制数及转换的方法. e.g. bitset<16> x; cin>>x; cout<<x.to_ulong()<<endl; 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=2e2; 5 const int INF=1e9; 6 int m,n; 7 int a[MAX]; 8 int total;

UVA - 1252 Twenty Questions

状压dp,用s表示已经询问过的特征,a表示W具有的特征. 当满足条件的物体只有一个的时候就不用再猜测了.对于满足条件的物体个数可以预处理出来 转移的时候应该枚举询问的k,因为实际上要猜的物品是不确定的,要么k是W所具有的,要么k不是W所具有的, 要保证能猜到那么就应该取最坏情况下的最小值,所以有转移方程:dp[s][a] = min(max(dp[s|1<<k][a],dp[s|1<<k][a|1<<k])). 询问特征可能转移到一个非法的状态,即满足条件的物品数量为0

UVA 1633-Dyslexic Gollum(状态压缩DP)

题目大意:求长度为N(1<=N<=400)且不含长度大于或等于K(1<=K<=10)的回文串的01串. 用d[i][j][u]表示长度为i且后11个01串组成数j且不含长度大于或等于u的01串有多少个. 如果j中含有长度至少为u的回文串,那么d[i][j][u]=0. 否则,假设d[i][j][u]可以由d[i-1][v][u]转移得来.根据状态的表示,那么v的低10位肯定是u的高10位,v的最高一位可以为0或1,即v=j/2或v=j/2+(1<<10). 程序将表打出