Football(概率dp+按位亦或运算的应用)

题目:POJ 3701

Description

Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, …, 2n. In each round of the tournament, all teams still in the tournament are placed in a list in order of increasing index. Then, the first team in the list plays the second team, the third team plays the fourth team, etc. The winners of these matches advance to the next round, and the losers are eliminated. After n rounds, only one team remains undefeated; this team is declared the winner.

Given a matrix P = [pij] such that pij is the probability that team i will beat team j in a match determine which team is most likely to win the tournament.

Input

The input test file will contain multiple test cases. Each test case will begin with a single line containing n (1 ≤ n ≤ 7). The next 2n lines each contain 2n values; here, the jth value on the ith line represents pij. The matrix P will satisfy the constraints that pij = 1.0 − pji for all i ≠ j, and pii = 0.0 for all i. The end-of-file is denoted by a single line containing the number −1. Note that each of the matrix entries in this problem is given as a floating-point value. To avoid precision problems, make sure that you use either the double data type instead of float.

Output

The output file should contain a single line for each test case indicating the number of the team most likely to win. To prevent floating-point precision issues, it is guaranteed that the difference in win probability for the top two teams will be at least 0.01.

Sample Input

2
0.0 0.1 0.2 0.3
0.9 0.0 0.4 0.5
0.8 0.6 0.0 0.6
0.7 0.5 0.4 0.0
-1

Sample Output

2

Hint

In the test case above, teams 1 and 2 and teams 3 and 4 play against each other in the first round; the winners of each match then play to determine the winner of the tournament. The probability that team 2 wins the tournament in this case is:

P(2 wins)  P(2 beats 1)P(3 beats 4)P(2 beats 3) + P(2 beats 1)P(4 beats 3)P(2 beats 4)
p21p34p23 + p21p43p24
= 0.9 · 0.6 · 0.4 + 0.9 · 0.4 · 0.5 = 0.396.

The next most likely team to win is team 3, with a 0.372 probability of winning the tournament.

题意:第一行给出一个数n,有2的n次方个队员进行比赛,两两组队比赛,每轮胜者再按顺序两两组队比赛,经过n轮,到最后生剩下的那一个即为获胜者,根据获胜概率求出获胜者编号(即:获胜概率最大的队员编号(队员编号从1~n)),接下来 m行m列的p[i][j]对应编号为i的队员战胜j的概率(m=2的n次方);

思路:这个题是一个概率dp,每个人在当前轮获胜的概率都与其在上一轮获胜的概率当前轮可能的竞争对手有关,并且一个人在当前轮的获胜概率就等于他在上一轮获胜的概率乘上它能够战胜其在当前轮可能的所有竞争对手的概率,用dp[j][i]表示编号为j的人在第i轮获胜的概率,则dp[j][i]=dp[j][i-1]*sum,sum=dp[k^j][i-1]*p[j][k^j]的和(k从2的i次方到2的(i+1)次方,注意这里的“^”为按位亦或(即两个数先转成二进制然后按二进制的每一位一一对应亦或的结果作为结果的二进制的对应的那一位的数值c++相关按位运算参考:https://blog.csdn.net/cyuyan112233/article/details/40758031),所有的k^j即为编号为j的人在第i轮可能的所有对手编号,因为比赛时按从前到后的顺序两两一组的,所以这样亦或一下正好就可以算出起对手编号!赛制规则如下图)点击此处查看赛制规则

注:上图编号按代码运算需要采用的0~m-1,但实际上是(1~m),所以最后结果要+1

完整代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int n;
double dp[130][8],p[130][130];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n&&n!=-1){
        int m=1<<n;
        memset(dp,0,sizeof(dp));
        memset(p,0,sizeof(p));
        for(int i=0;i<m;i++){
            for(int j=0;j<m;j++){
                cin>>p[i][j];
            }
            dp[i][0]=1;//初始时,每个人在第0轮,即一开始的胜率都是1
        }
        int ans;
        for(int i=0;i<n;i++){//枚举i轮
            ans=0;
            for(int j=0;j<m;j++){//枚举每个人
                double sum=0;
                for(int k=(1<<i);k<(1<<(i+1));k++){//枚举第j个人可能的对手k
                    sum+=dp[k^j][i]*p[j][k^j];
                }
                dp[j][i+1]=dp[j][i]*sum;
                if(dp[j][i+1]>dp[ans][i+1]) ans=j;//ans取当前轮获胜概率最大的人的编号
            }
        }
        cout<<ans+1<<endl;
    }
    return 0;
}
发布了176 篇原创文章 · 获赞 9 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Mr_Kingk/article/details/104250624