题目大意:Twenty Questions的游戏,要求你找出那个字符串
解题思路:一开始有想到枚举所有状态,然后进行与运算,再判断是否所有与的结果都不同,结果发现这是个错误思路,因为这个思路是用最小的问题区分出所有的字符串
有想过枚举所有状态,但感觉难度有点大,参考了别人的代码,发现参数可以为vector型的。。。,可以传这个vector,就好做了
用dp[All][s]表示All状态下,答案是s的集合时需要提问多少个问题,那么dp[All][s] = min(dp[All][s], max(solve(All | (1 << i), s | (1 << i), t1), solve(All | (1 << i), s , t2) + 1)
i表示问第i个是否为1,t1表示答案的集合(第i个是1),t2表示答案的集合(第i个不是0)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define maxn (1 << 12)
#define N 130
#define M 15
#define INF 0x3f3f3f3f
char str[N][M];
int dp[maxn][maxn];
int n, m;
int solve(int All, int s, vector<int> v) {
if(dp[All][s] != -1)
return dp[All][s];
if(v.size() <= 1)
return dp[All][s] = 0;
dp[All][s] = INF;
for(int i = 0; i < m; i++) {
if(All & (1 << i))
continue;
vector<int> t1;
vector<int> t2;
for(int j = 0; j < v.size(); j++)
if(str[v[j]][i] == '1')
t1.push_back(v[j]);
else
t2.push_back(v[j]);
dp[All][s] = min(dp[All][s], max(solve(All | (1 << i), s | (1 << i), t1), solve(All | (1 << i), s, t2)) + 1);
}
return dp[All][s];
}
int main() {
while(scanf("%d%d", &m, &n) != EOF && n + m) {
vector<int > tmp;
for(int i = 0; i < n; i++) {
scanf("%s", str[i]);
tmp.push_back(i);
}
memset(dp, -1, sizeof(dp));
printf("%d\n", solve(0,0,tmp));
}
return 0;
}