第 \(i\) 轮比赛相当于大小为 \(2^i\) 的小比赛里的单挑,赛场中点两侧的的可以两两单挑。
令 \(f(r,i)\) 表示第 \(r\) 轮中队伍 \(i\) 存活的概率,\(w(i,j)\) 为输入给出的 \(i\) 战胜 \(j\) 的概率,有
\[ f(r,i) = \sum{f(r-1,i) f(r-1,j)w(i,j)} \]
答案是 \(\max{f(n,i)}\)。
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 8;
double f[N][1 << N];
double w[1 << N][1 << N];
int main() {
int n;
while (~scanf("%d", &n)) {
if (n == -1) {
break;
}
int nn = (1 << n);
for (int i = 0; i < nn; i++) {
for (int j = 0; j < nn; j++) {
scanf("%lf", &w[i][j]);
}
}
for (int r = 1; r <= n; r++) {
for (int i = 0; i < nn; i++) {
f[r][i] = 0.0;
}
}
for (int i = 0; i < nn; i++) {
f[0][i] = 1.0;
}
for (int r = 0; r < n; r++) {
int len = (2 << r);
for (int s = 0; s < nn - len + 1; s += len) {
int t = s + len - 1;
int mi = (s + t) >> 1;
for (int i = s; i <= mi; i++) {
for (int j = mi + 1; j <= t; j++) {
f[r + 1][i] += f[r][i] * f[r][j] * w[i][j];
f[r + 1][j] += f[r][i] * f[r][j] * w[j][i];
}
}
}
}
double best = 0.0;
int bid = -1;
for (int i = 0; i < nn; i++) {
if (best < f[n][i]) {
bid = i;
best = f[n][i];
}
}
printf("%d\n", bid + 1);
}
return 0;
}