标签:style blog http io color os ar for sp
题意:
有n个长为m的各不相同的二进制数(允许存在前导0),别人已经事先想好n个数中的一个数W,你要猜出这个数。
每次只可以询问该数的第K为是否为1.
问采用最优询问策略,则最少需要询问多少次能保证猜到。
比如有1100 和 0110两个数,只需要询问第一或第三位数是否为1,即可猜中,因此答案为1.
分析:
d(s, a)表示已经询问了的集合s,在已经询问了的集合中W中为1的集合为a,还需要询问多少次。
如果下一次询问第k位,则询问次数为:
然后取所有k里的最小值即可。
预处理:
对于每个s和a,可以先把满足条件的数的个数记录下来,保存在cnt[s][a]里。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 6 const int maxm = 12, maxn = 130; 7 char object[maxn][maxm + 10]; 8 int d[1<<maxm][1<<maxm], cnt[1<<maxm][1<<maxm], vis[1<<maxm][1<<maxm]; 9 int m, n, kase = 0; 10 11 int dp(int s, int a) 12 { 13 if(cnt[s][a] <= 1) return 0; 14 if(cnt[s][a] == 2) return 1; 15 16 int& ans = d[s][a]; 17 if(vis[s][a] == kase) return ans; 18 vis[s][a] = kase; 19 20 ans = m; 21 for(int k = 0; k < m; ++k) 22 { 23 if(!(s&(1<<k))) 24 { 25 int s2 = s | (1<<k), a2 = a | (1<<k); 26 if(cnt[s2][a] >= 1 && cnt[s2][a2] >= 1) 27 { 28 int need = max(dp(s2, a2), dp(s2, a)) + 1; 29 ans = min(ans, need); 30 } 31 } 32 } 33 return ans; 34 } 35 36 int main() 37 { 38 //freopen("in.txt", "r", stdin); 39 while(scanf("%d%d", &m, &n) && n) 40 { 41 ++kase; 42 for(int i = 0; i < n; ++i) 43 scanf("%s", object[i]); 44 memset(vis, 0, sizeof(vis)); 45 memset(cnt, 0, sizeof(cnt)); 46 for(int i = 0; i < n; ++i) 47 { 48 int feature = 0; 49 for(int f = 0; f < m; ++f) 50 if(object[i][f] == ‘1‘) feature |= (1 << f); 51 for(int s = 0; s < (1<<m); ++s) 52 cnt[s][s&feature]++; 53 } 54 printf("%d\n", dp(0, 0)); 55 } 56 57 return 0; 58 }
UVa 1252 (状压DP + 记忆化搜索) Twenty Questions
标签:style blog http io color os ar for sp
原文地址:http://www.cnblogs.com/AOQNRMGYXLMV/p/4068756.html