POJ 3071 Football:概率dp

题目链接: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 }
原文地址:https://www.cnblogs.com/Leohh/p/7467312.html