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个。根据转移方程应该返回0。

#include<bits/stdc++.h>
using namespace std;

const int maxm = 11, maxn = 130;

int cnt[1<<maxm][1<<maxm], m, n, dp[1<<maxm][1<<maxm];

bitset<maxm> obj[maxn];
const int INF = 0x3fffffff;

void preDeal()
{
    for(int s = 0,M = 1<<m; s < M; s++){
        fill(cnt[s],cnt[s]+s+1,0);
        fill(dp[s],dp[s]+s+1,INF);
        for(int i = 0; i < n; i++){
            cnt[s][obj[i].to_ulong()&s]++;
        }
    }
}

int dfs(int s,int a)
{
    if(cnt[s][a] <= 1) return  0;
    int &ans = dp[s][a];
    if(ans<INF) return ans;
    for(int k = 0; k < m; k++){
        if(s&1<<k) continue;
        int ns = s|1<<k;
        ans = min(ans,max(dfs(ns,a),dfs(ns,a|1<<k))+1);
    }
    return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d\n",&m,&n),m){
        for(int i = 0; i < n; i++){
            cin>>obj[i];
        }
        preDeal();
        printf("%d\n",dfs(0,0));
    }
    return 0;
}
时间: 2024-10-11 22:27:29

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

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

链接: 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+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*

1252 - Twenty Questions(状态压缩DP)

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

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

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