POJ_3071 Football 概率dp

http://poj.org/problem?id=3071

题意:

有(1<<N)个人进行N次比赛,每次比赛都是第i个人和第i+1个人进行,赢的人能进入下一轮,输的人就不能继续比赛,N轮比赛之后,只会有一个人留下来,问谁最终留下来的概率最大。

思路:

概率dp,我们用dp[i][j]表示经过i场比赛之后,第j个人还没被淘汰的概率,那么状态转移方程就变成了:

dp[i][j] = sum{ dp[i-1][j] * dp[i-1][k] * P[j][k] } ,其中的k表示在第i轮有机会和i比赛的人的编号,P[j][k]表示jbeatsk的概率,最后只需要比较谁的概率最大就可以了。

代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define STOP() system("pause")
const int MAXN = 150 ;
int N , NN;
double P[MAXN][MAXN] ;
double dp[10][MAXN];


void solve(){
    for(int i=1;i<=NN;i++)
        dp[0][i] = 1 ;
    for(int i=1;i<=N;i++){
        int aa = 1 << (i-1) ;
        for(int j=1;j<=NN;j++){
            int s , e  ;
            s = 0  ;
            int cnt = 0 ;
            while( s + aa < j )   s += aa ,cnt ++ ;
            if( (cnt & 1) == 0 ){
                s += aa ;
                e = s + aa ; s = s + 1 ;
            }
            else{
                e = s ;
                s = s - aa  + 1 ;
            }
            dp[i][j] = 0 ;
            for(int k=s;k<=NN && k<=e;k++){
                dp[i][j] += dp[i-1][j] * dp[i-1][k] * P[j][k] ;
            }
        }
    }
    double _max = 0 ;
    int max_num ;
    for(int i=1;i<=NN;i++){
        if( dp[N][i] > _max ){
            _max = dp[N][i] ;
            max_num = i ;
        }
    }
    printf("%d\n",max_num);
}

int main(){
    while( scanf("%d",&N)==1){
        if(N == -1) break;
        NN = 1 << N ;
        for(int i=1;i<=NN;i++){
            for(int j=1;j<=NN;j++)
                scanf("%lf",&P[i][j]);
        }
        solve() ;
    }
    return 0 ;
}



你可能感兴趣的:(POJ_3071 Football 概率dp)