有n个物体的m个特征,每个物体用m位的01串表示,每次可以询问一个特征,问最少询问几次可以保证猜到
思路
状态压缩、动态规划
用两维表示,d(s, a),s表示已经询问的特征集,a表示已经具备的特征集,设要询问的下一个特征为k
min{ max{ d(s + {k}, a + {k}), d(s + {k}, a) + 1} }
边界是当有个物体符合a,不符合s-a中的特征,d(s, a) = 0
#include <bits/stdc++.h>
using namespace std;
const int maxn = 128 + 5;
const int maxs = 12;
int m, n;
int f[maxn];
int d[1<<maxs][1<<maxs];
int cnt[1<<maxs][1<<maxs];
bool vis[1<<maxs][1<<maxs];
int bitchange(const char *s){
int sum = 0;
for(int i = m - 1, j = 0; i >= 0; --i, ++j) {
if(s[i] == '1') sum |= (1 << j);
}
return sum;
}
int judge(int s, int a) {
int & val = cnt[s][a];
if(val != -1) return val;
val = 0;
for(int i = 0; i < n; ++i) {
int s_a = ((~a) & s);
if((f[i] & a) == a && (s_a & f[i]) == 0)
val++;
}
return val;
}
int dp(int s, int a) {
int & ans = d[s][a];
if(vis[s][a]) return ans;
vis[s][a] = true;
if(judge(s, a) == 1) return ans = 0;
ans = m;
for(int i = 0; i < m; ++i) if((s & (1 << i)) == 0){
int s0 = s | (1 << i), a0 = a | (1 << i);
ans = min(ans, max(dp(s0, a0), dp(s0, a)) + 1);
}
return ans;
}
int main()
{
while(scanf("%d%d",&m, &n) == 2){
if(m == 0 && n == 0) break;
memset(vis, false, sizeof(vis));
char s[20];
for(int i = 0; i < n; ++i) {
scanf("%s", s);
f[i] = bitchange(s);
}
memset(cnt, -1, sizeof(cnt));
printf("%d\n", dp(0, 0));
}
return 0;
}