Twenty Questions

题意:

有n个长度为m的二进制串,每个都是不同的。

为了把所有字符串区分开,你可以询问,每次可以问某位上是0还是1。

问最少提问次数,可以把所有字符串区分开来。

分析:

dp[s1][s2]: 表示提问的问题是s1集合,答案是s2时,还需要问几次才可以全部区分开

当问题集合为{s1}时, 如果还不能区分所有答案,那么就需要继续再问一个问题, { s1 | (1<<j),  当s1的j位上为0的时候 }

如果和答案s2相同的个数小于等于1,那么已经可以全部区分开了

如果还没区分开继续下一个问题,因为再最坏的情况下,要取答案s2的两种情况最大值

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define read freopen("in.txt", "r", stdin)
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
int n,m,dp[1<<11][1<<11];
int cas[150];
int dfs(int s1,int s2){
    if(dp[s1][s2]>=0)return dp[s1][s2];
    dp[s1][s2]=INF;
    int num=0;
    for(int i=0;i<n;++i)
        if((s1&cas[i])==s2)num++;
    if(num<=1)return dp[s1][s2]=0;
    for(int i=0;i<m;++i)
    if((s1&(1<<i))==0){
        dp[s1][s2]=min(dp[s1][s2],max(dfs((s1|(1<<i)),s2),dfs((s1|(1<<i)),(s2|(1<<i))))+1);
    }
    return dp[s1][s2];
}
int main()
{
    char str[20];
    while(~scanf("%d%d",&m,&n)){
        if(m==0&&n==0)break;
        memset(cas,0,sizeof(cas));
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<n;++i)
        {
            scanf("%s",str);
            for(int j=0;j<m;++j)
                if(str[j]==‘1‘)
                    cas[i]|=(1<<j);
        }
        printf("%d\n",dfs(0,0));
    }
return 0;
}
时间: 2024-10-03 14:55:52

Twenty Questions的相关文章

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不变,问某位为

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

十五 Twenty Questions Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 1252 Appoint description:  System Crawler  (2015-08-25) Description Consider a closed world and a set of features that are defined f

状压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 :

1252 - Twenty Questions(状态压缩DP)

经典的状态压缩DP .  有没有感觉这道题和什么东西有点像?  没错,是01背包 . 将特征看作物品 , 只不过这里的状态有点复杂, 需要用一个集合才能表示它, 所以我们用d[s][a]来表示,已经询问了特征集s , 假设我们要猜的物品是w ,w所具备的特征集为a ,此时还要询问的最小次数 .   显然a是s的子集,而且要注意本题的要求, 求的是最小化的最大询问次数 .也就是说无论猜哪个物品,猜这么多次一定能猜到 . 那么状态如何转移呢? 就像背包问题,对于一个特征k ,我们要抉择:要k还是不要

(状压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 1252 (状压DP + 记忆化搜索) Twenty Questions

题意: 有n个长为m的各不相同的二进制数(允许存在前导0),别人已经事先想好n个数中的一个数W,你要猜出这个数. 每次只可以询问该数的第K为是否为1. 问采用最优询问策略,则最少需要询问多少次能保证猜到. 比如有1100 和 0110两个数,只需要询问第一或第三位数是否为1,即可猜中,因此答案为1. 分析: d(s, a)表示已经询问了的集合s,在已经询问了的集合中W中为1的集合为a,还需要询问多少次. 如果下一次询问第k位,则询问次数为: 然后取所有k里的最小值即可. 预处理: 对于每个s和a

UVA-1252 Twenty Questions (状压DP)

题目大意:有n件物品,每件物品有m个特征,可以对特征进行询问,询问的结果是得知某个物体是否含有该特征,要把所有的物品区分出来(n个物品的特征都互不相同)最小需要多少次询问? 题目分析:定义dp(s,a)表示询问了的特征集合为s,物体含有特征集合a中的所有特征,但不含特征集合 s^a 中的所有特征时还需的最少询问次数.状态转移方程为dp(s,a)=min(max(dp(s|(1<<k),a|(1<<k)),dp(s|(1<<k),a))+1). 用记忆化搜索的形式实现即可