POJ 3071 Football 【概率dp】

题目链接:http://poj.org/problem?id=3071

题目大意:给出 2^n 个队伍,队伍之间 1-2,3-4,5-6,这样分别两两淘汰,之后又是邻接队伍进行淘汰赛。给出两两之间A打败B的可能性,问哪只队伍最终获胜的可能性最大,并输出队伍序号。

思路:

1.概率dp题,关键在于选好dp的“ 内涵 ”, 跟回合有关,并且需要领接的队伍才能进行比赛。所以dp[i][j]代表第i轮第j个队伍存活的概率,最终我们只需要遍历dp[n][j](0~2^n - 1), 得到存活率最大的队伍就是答案。

2.还要运用到小技巧,每个队伍编号 -1 ,使其可以用位运算 ^1来判断是否在该轮邻接。

代码里的注释很详细

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define mem(a, b) memset(a, b, sizeof(a))
 4 
 5 double p[150][150];
 6 double dp[10][150]; //代表第i轮第j个队伍存活的概率 
 7 
 8 int main()
 9 {
10     int n;
11     while(scanf("%d", &n) != EOF)
12     {
13         if(n == -1)
14             break;
15         mem(dp, 0);  //WA了一次在这里,忘了清0. 
16         int limit = 1 << n;//队伍编号处理为 0 ~ limit - 1 
17         for(int i = 0; i < limit; i ++)//比赛未开始前每个队伍存活概率都为1 
18             dp[0][i] = 1.0;
19         for(int i = 0; i < limit; i ++)
20         {
21             for(int j = 0; j < limit; j ++)
22             {
23                 scanf("%lf", &p[i][j]);
24             }
25         }
26         for(int i = 1; i <= n; i ++)//枚举第几轮 
27         {
28             for(int j = 0; j < limit; j ++)//枚举获胜队伍 
29             {
30                 for(int k = 0; k < limit; k ++)//枚举失败队伍 
31                 {
32                     if((j >> (i - 1) ^ 1) == k >> (i - 1) && j != k)//满足在同一轮会相遇,即邻接条件 
33                     {
34                         dp[i][j] += dp[i - 1][j] * dp[i - 1][k] * p[j][k];//两支比赛队伍上一轮必须都存活,并且在该轮j赢了k 
35                     }
36                 }
37             }
38         }
39         double maxx = -1.0;
40         int ans;
41         for(int i = 0; i < limit; i ++)
42             if(maxx < dp[n][i])
43             {
44                 maxx = dp[n][i];
45                 ans = i + 1;
46             }
47         printf("%d\n", ans);
48     }
49     return 0;
50 }
View Code

 

posted @ 2019-06-04 23:43  缘未到  阅读(111)  评论(0编辑  收藏  举报