题目链接: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;
}