题目链接:http://poj.org/problem?id=3071
题意:
给定n,有2^n支队伍参加足球赛。
给你所有的p[i][j],表示队伍i打败队伍j的概率。
淘汰赛制。第一轮(1,2)两队比、(3,4)比、(5,6)比...共进行n轮比赛后产生冠军。
问你冠军最有可能是哪支队伍。
题解:
表示状态:
dp[i][j] = probability to win
第i支队伍能够参加第j轮比赛的概率。
找出答案:
i of max dp[i][n+1]
n轮比赛后,冠军该参加第n+1轮比赛(不存在的)。
如何转移:
now: dp[i][j]
dp[i][j+1] = ∑ (dp[i][j] * dp[k][j] * p[i][k]) (加法原理)
k: 第j轮比赛和i比的队伍
P(i晋级到j+1轮) = ∑ (P(i晋级到j轮) * P(k晋级到j轮) * P(i打败k))
怎样枚举k:
将所有队伍从0开始编号,并用二进制表示。
第i支战队第j轮会碰到的对手是:将i化为二进制,从右往左开始算,第j-1位会不同,第j位开始要相同,其余位任意的所有数。
边界条件:
dp[i][1] = 1
others = 0
注:本题居然卡cin。。。 (*`皿´*)ノ
AC Code:
1 // state expression: 2 // dp[i][j] = probability to win 3 // i: which team 4 // j: which round 5 // 6 // find the answer: 7 // i of max dp[i][n+1] 8 // 9 // transferring: 10 // dp[i][j+1] = sigma (dp[i][j] * dp[k][j] * p[i][k]) 11 // 0<=t<(1<<(j-1)) 12 // k = (((i>>(j-1))^1)<<(j-1))|t 13 // 14 // boundary: 15 // dp[i][1] = 1 16 #include <iostream> 17 #include <stdio.h> 18 #include <string.h> 19 #define MAX_N 10 20 #define MAX_T 150 21 22 using namespace std; 23 24 int n; 25 int ans; 26 double p[MAX_T][MAX_T]; 27 double dp[MAX_T][MAX_N]; 28 29 void read() 30 { 31 for(int i=0;i<(1<<n);i++) 32 { 33 for(int j=0;j<(1<<n);j++) 34 { 35 scanf("%lf",&p[i][j]); 36 } 37 } 38 } 39 40 void solve() 41 { 42 memset(dp,0,sizeof(dp)); 43 for(int i=0;i<(1<<n);i++) 44 { 45 dp[i][1]=1; 46 } 47 for(int j=1;j<=n;j++) 48 { 49 for(int i=0;i<(1<<n);i++) 50 { 51 for(int t=0;t<(1<<(j-1));t++) 52 { 53 int k=((((i>>(j-1))^1)<<(j-1))|t); 54 dp[i][j+1]+=dp[i][j]*dp[k][j]*p[i][k]; 55 } 56 } 57 } 58 double maxn=0; 59 for(int i=0;i<(1<<n);i++) 60 { 61 if(dp[i][n+1]>maxn) 62 { 63 maxn=dp[i][n+1]; 64 ans=i+1; 65 } 66 } 67 } 68 69 void print() 70 { 71 printf("%d ",ans); 72 } 73 74 int main() 75 { 76 while(scanf("%d",&n)!=EOF) 77 { 78 if(n==-1) break; 79 read(); 80 solve(); 81 print(); 82 } 83 }