题目链接:http://codeforces.com/contest/859/problem/D
题意:一个排球比赛,开始2^n个队,淘汰制,每一把比赛淘汰一半的人,然后给出了每个人赢其他人的概率,问一个人正确预测比赛结果的最大期望是多少?
解法:概率DP好题。比较久没写过概率DP了。复习一下,概率DP一般是dp[i]代表i到终点的期望,然后dp[i] = sigma(dp[j]+代价)*概率。。这道题比较特殊,我们可以把比赛过程看成在二叉树上的概率DP。win[i][j]表示在根节点为i第j个人赢的概率,e[i][j]代表第根节点为i第j个赢的期望,pro[i][j]表示第i个人赢第j个人的概率。然后按照概率DP的基本方法转移即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
double win[maxn][maxn], e[maxn][maxn], pro[maxn][maxn];
int n, m, x;
void DFS(int p, int l, int r){
if(l+1==r) win[p][l]=1,e[p][l]=0;
else{
int mid=(l+r)/2;
DFS(p*2, l, mid);
DFS(p*2+1, mid, r);
for(int i=l; i<mid; i++)
for(int j=mid; j<r; j++)
win[p][i] += win[p*2][i]*win[p*2+1][j]*pro[i][j];
for(int i=l; i<mid; i++)
for(int j=mid; j<r; j++)
e[p][i] = max(e[p][i], win[p][i]*(r-l)/2+e[p*2][i]+e[p*2+1][j]);
for(int i=mid; i<r; i++)
for(int j=l; j<mid; j++)
win[p][i] += win[p*2+1][i]*win[p*2][j]*pro[i][j];
for(int i=mid; i<r; i++)
for(int j=l; j<mid; j++)
e[p][i] = max(e[p][i], win[p][i]*(r-l)/2+e[p*2+1][i]+e[p*2][j]);
}
}
int main()
{
scanf("%d", &n);
m = 1<<n;
for(int i=0; i<m; i++){
for(int j=0; j<m; j++){
scanf("%d", &x);
pro[i][j] = 0.01*x;
}
}
DFS(1, 0, m);
double maxv = 0;
for(int i=0; i<m; i++) maxv = max(maxv, e[1][i]);
printf("%.10f\n", maxv);
return 0;
}