Twenty Questions UVA - 1252 (状压dp)
Twenty Questions
题意: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 }