题意
抓小偷,先从目击者0开始,选择犯罪可能性最大的一个人,如果有多人相同,选择哪个都有可能。然后更新所有人的犯罪可能性。
问如果一个人是小偷,最少几轮能被发现。
题解
暴力枚举,状态压缩DP
两重循环计算每个人的在所有人中的最大怀疑值,若等于指定人则更新答案。
int n;
vector<string> s;
int memo[18][1<<18];
int f(int k, int mask)
{
int & res = memo[k][mask];
if (res == -1) {
int susp = -1;
int best_time = 0;
// get suspicions.
// for the maximum suspicion, remember the minimum time
for (int i = 1; i < n; i++) {
if ( !( (1<<i) & mask) ) {
int su = 0;
for (int j = 0; j < n; j++) {
if ( (1<<j) & mask) {
su = std::max<int>(su, s[j][i] - '0');
}
}
int t = 1 + ( (i == k)? 0 : f(k, mask | (1<<i) ) );
if (su > susp) {
// new maximum suspicion
susp = su;
best_time = t;
} else if ( (su == susp) && (best_time > t) ) {
// update minimum time
best_time = t;
}
}
}
res = best_time;
}
return res;
}
int reveal(vector<string> s)
{
// init memo table with -1s
memset( memo, -1, sizeof(memo) );
this->s = s;
n = s.size();
int res = 0;
for (int i = 0; i < n; i++) {
res += i * f(i, 1);
}
return res;
}