题意:给定n个长度为m的串(n<=50,m<=20),保证每个串互不相同.每次可以问目标串一个位置上的字母,问最终猜出目标串的期望次数.
解法:状态压缩dp.
Let dp[mask] be the expected number of questions from state mask. When we try to ask question pos in state mask, the chance that we will not guess correctly right away is equal to the fraction frac = bitCount(d[mask ^ (1<<pos)]) / bitCount(d[mask]).
So dp[mask] is equal to the average of 1 + dp[mask ^ (1<<pos)] * frac, for all pos not in mask.
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
#include <iostream>
#include <iomanip>
using namespace std;
string s[55];
long long bad[1 << 20];
double dp[1 << 20];
int n, m;
int main()
{
ios::sync_with_stdio(false);
cout << fixed << setprecision(16);
cin >> n;
for (int i = 0; i < n; ++ i) {
cin >> s[i];
}
m = (int)s[0].length();
for (int i = 0; i < n; ++ i) {
for (int j = i + 1; j < n; ++ j) {
int diff = 0;
for (int k = 0; k < m; ++ k) {
if (s[i][k] == s[j][k]) {
diff |= 1 << k;
}
}
bad[diff] |= (1ll << i) + (1ll << j);
}
}
for (int i = (1 << m) - 2; i >= 0; -- i) {
for (int j = 0; j < m; ++ j) {
if (((i >> j) & 1) == 0) {
bad[i] |= bad[(i | (1 << j))];
}
}
if (bad[i] == 0) {
continue;
}
int c = m - __builtin_popcount(i);
int d = __builtin_popcountll(bad[i]);
for (int j = 0; j < m; ++ j) {
if (((i >> j) & 1) == 0) {
dp[i] += dp[i | 1 << j] * __builtin_popcountll(bad[i | 1 << j]) / d;
}
}
dp[i] = 1. + dp[i] / c;
}
cout<<dp[0]<<endl;
return 0;
}