Football POJ - 3071 (简单概率dp)

题面:

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

 题意:

        题意比较简单,现在有要打 n 场比赛,便有 2^n 支队伍,给每两个队伍之间比赛的胜率,求哪个队伍成为冠军的概率最大,输出这个队伍。

思路:

        首先经典概率正推,定义一个合适的状态,由于要保证推得每个队伍在最后一个比赛获胜的概率,所以状态 dp [ i ] [ j ] 定义为第j支队伍在第 i 场比赛获胜的概率。显然,不知道的是,第 i 场比赛时,这支队伍会和谁打,所以需要从头开始遍历,有需要保证和他比赛的队伍也之前获胜了,所以转移方程如下所示:

        dp [ i ] [ j ] = dp[ i - 1] [ j ] * dp[ i - 1] [ k ] * p [ j ] [ k ] ( 0 < k < 2 ^ n )

        这个时候我们还得考虑另一个问题,虽然判断的是两者到这时候都存活的几率,但是会有重复,即两者身处一个子树上,此时会重复,两者之前已经比较过了,但是由于两者的存活情况不同,所以会计算重复,因此要计算出来两者不重复的条件才可使用递推方程。

        当二者之前没有打过的时候,上一局只要不在一条子树上就是该条件,即上一轮两个人没有对打,由二叉树的知识可以知道,到第 i 场时,第  j 支队伍碰到的队伍不能是左半侧的队伍,即第 1 << i 为左半部分的话,此时 k 应该不能和它一个部分,即k最后一场比赛的位置和 i 不一样,所以利用位运算,我们可以知道,j 最后一次比赛的话 ,所处位置是j >> ( i - 1 ),同理,k 所处位置是 k >> ( i - 1 ),既然二者位置不相同,那便是两式子不相等,所以判断条件也可以得到了:

        ((j>>(i-1))^1)==(k>>(i-1))

        接下来的实现就很容易了,记录下来每个可能,进行叠加,最后比较便可以了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=15;
const int mod=1e9+7;
double dp[150][150],p[150][150];
int main()
{
    int n;
    while(cin>>n){
        if(n==-1)break;
        int num=1<<n;
        memset(dp,0,sizeof(dp));
        for(int i=0;i<num;i++){
            for(int j=0;j<num;j++)
                cin>>p[i][j];
        }
        for(int i=0;i<num;i++)dp[0][i]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<num;j++){
                for(int k=0;k<num;k++){
                    if(((j>>(i-1))^1)==(k>>(i-1))){
                        dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k];
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<num;i++){
            if(dp[n][i]>dp[n][ans])
                ans=i;
        }
        cout<<ans+1<<endl;
    }
    return 0;
}
/*
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
*/

有参考,侵删。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值