Twenty Questions
https://odzkskevi.qnssl.com/15b7eb4cd1f75f63cee3945b0b845e4f?v=1508411736
【题解】
dp[S1][S2]表示已经询问了S1,确定有S2,还需要至少多少次询问
dp[S1][S2] = max(min(dp[S1 | k][S2 | k], dp[S1 | k, S2 | j)) + 1
即枚举询问哪一个k,得到答复是有/没有中取还需要的询问次数最大的,然后
在所有的k中找最小的,表示到了S1,S2这个状态我要去询问k
预处理cnt[S1][S2]表示S2是S1的子集且属性为S2的物体的个数
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 #include <sstream> 7 #include <vector> 8 #include <string> 9 #include <cmath> 10 #include <queue> 11 #define min(a, b) ((a) < (b) ? (a) : (b)) 12 #define max(a, b) ((a) > (b) ? (a) : (b)) 13 14 inline void swap(int &a, int &b) 15 { 16 int tmp = a;a = b;b = tmp; 17 } 18 19 inline void read(int &x) 20 { 21 x = 0;char ch = getchar(), c = ch; 22 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 23 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 24 if(c == '-')x = -x; 25 } 26 27 const int INF = 0x3f3f3f3f; 28 const int MAXN = 128 + 5; 29 const int MAXM = 11 + 2; 30 31 int ma,dp[1 << MAXM][1 << MAXM], cnt[1 << MAXM][1 << MAXM], n, m, num[MAXN]; 32 char s[MAXM]; 33 /* 34 dp[s1][s2]表示已经询问了s1,确定有s2,还需要询问多少次 35 */ 36 int DP(int s1, int s2) 37 { 38 if(cnt[s1][s2] <= 1)return 0; 39 if(dp[s1][s2] > -1)return dp[s1][s2]; 40 dp[s1][s2] = INF; 41 for(register int i = 0;i < m;++ i) 42 { 43 if(s1 & (1 << i))continue; 44 dp[s1][s2] = min(dp[s1][s2], max(DP(s1 | (1 << i), s2), DP(s1 | (1 << i), s2 | (1 << i))) + 1); 45 } 46 return dp[s1][s2]; 47 } 48 49 int main() 50 { 51 while(scanf("%d %d", &m, &n) != EOF && m + n) 52 { 53 memset(num, 0, sizeof(num)); 54 memset(dp, -1, sizeof(dp)); 55 memset(cnt, 0, sizeof(cnt)); 56 for(register int i = 1;i <= n;++ i) 57 { 58 scanf("%s", s); 59 for(register int j = 0;j < m;++ j) 60 if(s[j] == '1') num[i] |= (1 << j); 61 } 62 ma = 1 << m; 63 for(register int s1 = 0;s1 < ma - 1;++ s1) 64 for(register int i = 1;i <= n;++ i) 65 ++ cnt[s1][s1 & num[i]]; 66 printf("%d ", DP(0,0)); 67 } 68 return 0; 69 }