Twenty Questions UVA - 1252 (状压dp)

Twenty Questions

 UVA - 1252 

题意:n个物体,每个物体有m个特征,问最少询问几次可以唯一确定一个物体。

 

d[s][a]表示已经问了s中为1的位置,状态为a时最少还需要问几次

(简言之s保存的是询问过的位置。。。)

【我们每次把物品中已经询问的位置(即s为1的那些位置)都和状态a一致的选出来,如果只有一个,说明我们已经找到,否则,继续询问备选缩小范围。】

a是不确定的,每次决策a的那个位置可能是0或1,我们要求的是不管那位0或者1,都可以唯一确定a最少还要问的次数,即两种状态下取较大的次数。

要求最优决策下的最小次数,每次决策更新最小值ans。

当所有物品中满足a的个数等于1时,得到一个次数返回比较即可。

 1 #include <cstdio>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 const int maxn = 1 << 12;
 6 const int INF = 0x3f3f3f3f;
 7 
 8 string str;
 9 int w[130];
10 int d[maxn][maxn];
11 int m, n;
12 
13 int dp(int s, int a)
14 {
15     int& ans = d[s][a];
16     if (ans != INF)  return ans;
17     int cnt = 0;
18     for (int i = 0; i<n; i++)
19         //边界条件判断,如果cnt<=1,则说明能判断出来了
20     if ((w[i] & s) == a)  cnt++;
21     if (cnt <= 1){ d[s][a] = 0; return 0; }
22 
23     for (int i = 0; i<m; i++)
24     {
25         if (s&(1 << i))continue;
26         ans = min(ans, max(dp(s | 1 << i, a | 1 << i), dp(s | 1 << i, a)) + 1);
27     }
28     return ans;
29 }
30 
31 int main()
32 {
33     while (cin>>m>>n &&n&&m)
34     {
35         memset(w, 0, sizeof(w));
36         memset(d, INF, sizeof(d));
37         for (int i = 0; i<n; i++)
38         {
39             cin >> str;
40             for (int j = 0; str[j]; j++)
41             if (str[j] == '1')  w[i] |= (1 << j);
42         }
43         printf("%d\n", dp(0,0));
44     }
45 }
View Code

 

posted @ 2017-08-24 11:07  yijiull  阅读(204)  评论(0编辑  收藏  举报