題目大意
有n個長度為m的二進位串,每個都是不同的。
為了把所有字串區分開,你可以詢問,每次可以問某位上是0還是1。
問最少提問次數,可以把所有字串區分開來。
思路
f[s1][s2]: 表示提問的問題是{s1}集合,答案是{s2}時,還需要問幾次才可以全部區分開
當問題集合為{s1}時, 如果還不能區分所有答案,那麼就需要繼續再問一個問題,
那麼可以推出下一個問題的集合為:
nextQuestions = { s1 | (1<<k), 當s1的k位上為0的時候 }
那麼可以得到:
f[s1][s2] = 0, 如果和答案s2相同的個數小於等於1,那麼已經可以全部區分開了,還要詢問0次
f[s1][s2] = { min(f[nextQuestions][s1], f[nextQuestions][s1^(1<<k)]), 當s1的k位上為0時}
代碼
/**==========================================* This is a solution for ACM/ICPC problem** @source:uva-1252 Twenty Question* @type: 記憶化搜尋* @author: shuangde* @blog: blog.csdn.net/shuangde800* @email: zengshuangde@gmail.com*===========================================*/ #include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<queue>#include<cmath>#include<cstring>using namespace std; typedef long long int64;const int INF = 0x3f3f3f3f;const double PI = acos(-1.0); const int MAXN = 130;int n, m; int p[MAXN];int f[(1<<11)+10][(1<<11)+10];// www.bianceng.cn int dfs(int s1, int s2){if(f[s1][s2] != INF) return f[s1][s2]; int cnt = 0;for(int i = 0; i < n; ++i)if( (p[i] & s1) == s2)++cnt; if(cnt <= 1){f[s1][s2] = 0;return 0;} for(int i=0; i<m; ++i){if( s1&(1<<i) ) continue;int nextQuest = s1 | (1<<i);int& d = f[s1][s2];d = min(d, max(dfs(nextQuest, s2), dfs(nextQuest, s2^(1<<i)))+1);}return f[s1][s2];} int main(){ char str[130];while(~scanf("%d%d", &m, &n) && n+m){ for(int i = 0; i < n; ++i){scanf("%s", str);p[i] = 0;for(int j = 0; str[j]; ++j)if(str[j] == '1')p[i] |= 1<<j;}memset(f, INF, sizeof(f));printf("%d\n", dfs(0, 0));}return 0;}