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个物体之一),由你来猜。
你每次可以询问一个特征,然后我会告诉你:我心里的物体是否具备这个特征。
当你确定答案之后,就把答案告诉我(告知答案不算“询问”)。
如果你采用最优策略,最少需要询问几次能保证猜到?
例如,有两个物体:1100和0110,只要询问特征1或者特征3,就能保证猜到。

分析:

为了叙述方便,设“心里想的物体”为W。首先在读入时把每个物体转化为一个二进制整数。
不难发现,同一个特征不需要问两遍,所以可以用一个集合k表示已经询问的特征集。
在这个集合k中,有些特征是W所具备的,剩下的特征是W不具备的。
用集合c来表示“已确认物体W具备的特征集”,则c一定是k的子集。
设d(k,c)表示已经问了特征集k,其中已确认W所具备的特征集为c时,还需要询问的最小次数。
如果下一次提问的对象是特征i(这就是“决策”),则询问次数为:max{d(k+{i},c+{i}),d(k+{i},c)}+1。
考虑所有的i,取最小值即可。边界条件为:如果只有一个物体满足“具备集合c中的所有特征,
但不具备集合k-c中的所有特征”这一条件,则d(k,c)=0,因为无须进一步询问,已经可以得到答案。
因为c为k的子集,所以状态总数为3^m,时间复杂度为O(m*3^m)。
对于每个k和c,可以先把满足该条件的物体个数统计出来,保存在amt[k][c],避免状态转移的时候重复计算。
统计amt[k][c]的方法是枚举k和物体,时间复杂度为O(n*2^m),对于本题来说可以忽略不计。

代码:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4
 5 const int INF = 0x3f3f3f3f;
 6 const int UPM = 11;
 7 const int UPN = 128;
 8 int n, m, d[1<<UPM][1<<UPM], amt[1<<UPM][1<<UPM];
 9 char s[UPN+5][UPM+5];
10
11 void init() {
12     int u = 1<<m;
13     for(int k = 0; k < u; k++) {
14         amt[k][0] = 0;
15         d[k][0] = INF;
16         for(int c = k; c; c = k&(c-1)) amt[k][c] = 0, d[k][c] = INF;
17     }
18     for(int t = 0; t < n; t++) {
19         int c = 0;
20         for(int i = 0; i < m; i++) if(s[t][i] == ‘1‘) c |= (1<<i);
21         for(int k = 0; k < u; k++) amt[k][k&c]++;
22     }
23 }
24
25 int dp(int k, int c) {
26     int& res = d[k][c];
27     if(res != INF) return res;
28     if(amt[k][c] < 2) return res = 0;
29     for(int i = 0; i < m; i++) {
30         if(k&(1<<i)) continue;
31         int k2 = k|(1<<i), c2 = c|(1<<i);
32         int need = max(dp(k2,c), dp(k2,c2));
33         res = min(res, need);
34     }
35     return res += 1;
36 }
37
38 int main() {
39     while(scanf("%d%d", &m, &n) && m) {
40         for(int i = 0; i < n; i++) scanf("%s", s[i]);
41         init();
42         printf("%d\n", dp(0,0));
43     }
44     return 0;
45 }

原文地址:https://www.cnblogs.com/hkxy125/p/9746198.html

时间: 2024-10-13 14:40:37

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*

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

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