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 feature can

be answered with yes" orno”. Using those features, we can identify any object from the rest of the objects

in the world. In other words, each object can be represented as a fixed-length sequence of booleans. Any

object is different from other objects by at least one feature.

You would like to identify an object from others. For this purpose, you can ask a series of questions to

someone who knows what the object is. Every question you can ask is about one of the features. He/she

immediately answers each question with yes" orno” correctly. You can choose the next question after you

get the answer to the previous question.

You kindly pay the answerer 100 yen as a tip for each question. Because you don’t have surplus money, it is

necessary to minimize the number of questions in the worst case. You don’t know what is the correct answer,

but fortunately know all the objects in the world. Therefore, you can plan an optimal strategy before you start

questioning.

The problem you have to solve is: given a set of boolean-encoded objects, minimize the maximum number of

questions by which every object in the set is identifiable.

Input

The input is a sequence of multiple datasets. Each dataset begins with a line which consists of two integers, m

and n: the number of features, and the number of objects, respectively. You can assume 0 < m 11 and 0 <

n 128. It is followed by n lines, each of which corresponds to an object. Each line includes a binary string of

length m which represent the value (yes" orno”) of features. There are no two identical objects.

The end of the input is indicated by a line containing two zeros. There are at most 100 datasets.

Output

For each dataset, minimize the maximum number of questions by which every object is identifiable and

output the result.

Sample Input

8 1

11010101

11 4

00111001100

01001101011

01010000011

01100110001

11 16

01000101111

01011000000

01011111001

01101101001

01110010111

4643 - Twenty Questions 1/301110100111

10000001010

10010001000

10010110100

10100010100

10101010110

10110100010

11001010011

11011001001

11111000111

11111011101

11 12

10000000000

01000000000

00100000000

00010000000

00001000000

00000100000

00000010000

00000001000

00000000100

00000000010

00000000001

00000000000

9 32

001000000

000100000

000010000

000001000

000000100

000000010

000000001

000000000

011000000

010100000

010010000

010001000

010000100

010000010

010000001

010000000

101000000

100100000

100010000

100001000

100000100

100000010

100000001

100000000

111000000

110100000

110010000

110001000

110000100

110000010

110000001

110000000

0 0

Sample Output

0

2

4


/* ***********************************************
Author        :CKboss
Created Time  :2015年02月22日 星期日 14时49分48秒
File Name     :UVA1252.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

const int maxn=3000;

int n,m;
int num[300];
int dp[maxn][maxn];
int cnt[maxn][maxn];

void init()
{
    memset(dp,-1,sizeof(dp));
    memset(cnt,0,sizeof(cnt));
}

void dfs(int s,int a) /// 已经枚举特征s,w具有特征a
{
    if(dp[s][a]!=-1) return ;
    if(cnt[s][a]<=1)
    {
        dp[s][a]=0; return ;
    }
    for(int i=0;i<m;i++)
    {
        if(s&(1<<i)) continue ;
        int ns=s|(1<<i);
        int na=a|(1<<i);
        dfs(ns,a); dfs(ns,na);
        if(dp[s][a]==-1)
            dp[s][a]=max(dp[ns][a],dp[ns][na])+1;
        else
            dp[s][a]=min(dp[s][a],max(dp[ns][a],dp[ns][na])+1);
    }
}

int main() {
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

    while(scanf("%d%d",&m,&n)!=EOF)
    {
        if(n==0&&m==0) break;
        init();
        for(int i=0;i<n;i++)
        {
            char temp[20];
            int ans=0;
            scanf("%s",temp);
            for(int j=0;j<m;j++)
                if(temp[j]==‘1‘) ans|=(1<<j);
            num[i]=ans;
        }
        for(int i=0;i<(1<<m);i++)
            for(int j=0;j<n;j++)
                cnt[i][num[j]&i]++;
        dfs(0,0);
        printf("%d\n",dp[0][0]);
    }
    return 0;
}
时间: 2024-10-17 07:58:12

UVA 1252 Twenty Questions 状压DP的相关文章

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*

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

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

UVA 11825 Hackers&#39; Crackdown 状压DP

感觉白书上的做法很神! 首先状压表示电脑之间的联通关系,然后预处理出所有关闭电脑的组合达到的状态,然后枚举每个状态并且枚举每个状态的所有子集,之后无脑递推就木有了. 关于枚举一个状态所有子集的小技巧:假设当前状态是S0 有 for s = s0; s != 0; s =  (s - 1) & s0 #include <cstdio> #include <cstring> #include <iostream> #include <map> #incl

UVA 11691 - Allergy Test(状压dp+贪心)

题目链接:11691 - Allergy Test 题意:这题题意看了老半天都没弄懂,好在后面找到个PPT,上面有中文题意- -,不过上面的做法是纯贪心,挺巧妙的但是感觉有点不靠谱, 下载地址:http://par.cse.nsysu.edu.tw/~advprog/advprog2011/11691.ppt 給N種過敏原的存活期,每天可把一種過敏原注入人體內.若有兩個以上過敏原存活於人體中,則無法進行實驗(也就是每種過敏原都必須有一天是單獨存活於人體中).實驗結束於最後的過敏原死亡的那天,求最

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 - 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 11825 Hackers’ Crackdown 状压DP枚举子集势

Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed computer system which is a prime target for hackers. The system is basically a set of N computer nodes with each of them running a set of Nservices. Note