@vjudge
状压
可以这样设计状态
d f s ( s , a ) dfs(s,a) dfs(s,a)表示当前已经猜测的集合,目前还没有确定的数在 s s s集合里面的共同特征为 a a a,还要猜几次
枚举下一次猜的位为 k k k
对于当前状态的答案是
s u m = m a x ( d f s ( s ∣ 2 k , a ) , d f s ( s ∣ 2 k , a ∣ 2 k ) ) + 1 sum=max(dfs(s|2^k,a),dfs(s|2^k,a|2^k))+1 sum=max(dfs(s∣2k,a),dfs(s∣2k,a∣2k))+1
对于每个 k k k,取答案的最小值
至于边界,若满足状态 ( s , a ) (s,a) (s,a)的数只有1个,则不用再猜;若还有2个,则再猜一次;若还有更多,则 d f s dfs dfs
Code:
#include <bits/stdc++.h>
#define maxn 2110
using namespace std;
int cnt[maxn][maxn], dp[maxn][maxn], power[25], vis[maxn][maxn], n, m, kase;
char s[maxn];
int dfs(int s, int a){
if (cnt[s][a] == 1) return 0;
if (cnt[s][a] == 2) return 1;
if (vis[s][a] == kase) return dp[s][a];
vis[s][a] = kase;
int ans = m;
for (int i = 1; i <= m; ++i)
if (!(s & power[i - 1])){
int S = s | power[i - 1], A = a | power[i - 1];
ans = min(ans, 1 + max(dfs(S, A), dfs(S, a)));
}
return dp[s][a] = ans;
}
int main(){
power[0] = 1;
for (int i = 1; i <= 20; ++i) power[i] = power[i - 1] << 1;
while (1){
scanf("%d%d", &m, &n);
if (m == 0 && n == 0) break;
++kase;
for (int i = 0; i < power[m]; ++i)
for (int j = 0; j < power[m]; ++j) cnt[i][j] = 0;
for (int i = 1; i <= n; ++i){
scanf("%s", s + 1);
int x = 0;
for (int j = 1; j <= m; ++j)
x = (x << 1) | (s[j] == '1');
for (int j = 0; j < power[m]; ++j) ++cnt[j][j & x];
}
printf("%d\n", dfs(0, 0));
}
return 0;
}