zoukankan      html  css  js  c++  java
  • POJ 3071 Football(概率DP)

    Football
    Time Limit: 1000MS   Memory Limit: 65536K
    Total Submissions: 3729   Accepted: 1905

    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.


    编号分别为1、2、3……2^n的2^n个队伍參加比赛,每一轮相邻的两两比赛,胜者晋级下一轮,负者淘汰,直到仅仅剩下一支队伍。

    基本思路:dp[i][j]表示第i轮比赛j号队胜利的概率,第i轮j要获胜,首先第(i-1)轮j要获胜,(所以dp[0][j]要初始化为1),用k表示能与j在第i轮比赛中相遇的对手。并且假设j与k要相遇。k也必须在第(i-1)轮中获胜,所以状态转移方程为dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k],注意。是相加。即把遇到每一个对手且获胜相加就是j在这一轮获胜的总概率。


    状态转移方程得到了,下一个点就是找到第i轮j可能遇到的对手。

    有非常多种方法,比方第一份代码就是通过标记记录j与k是否在第i轮之前交手,假设vis[j][k]=1,那么他们必然有一个被淘汰,就不可能在第i轮相遇。(k的范围的获得详见代码);第二份代码推断的方式就比較简单了。通过位来进行推断,自己能够带几组数据试一试。规律基本就能发现了。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int MAXN=(1<<7)+5;//注意括号
    double p[MAXN][MAXN],dp[10][MAXN];
    int vis[MAXN][MAXN];
    int n;
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
        while(scanf("%d",&n)!=EOF&&n!=-1)
        {
            int people=1<<n;
            for(int i=0;i<people;i++)
                for(int j=0;j<people;j++)
                    scanf("%lf",&p[i][j]);
            memset(dp,0,sizeof(dp));
            memset(vis,0,sizeof(vis));
            for(int i=0;i<people;i++)
            {
                dp[0][i]=1;
                vis[i][i]=1;
            }
            for(int i=1;i<=n;i++)
                for(int j=0;j<people;j++)
                {
                    if(i==1)
                    {
                        dp[i][j]=p[j][j/2*4+1-j];
                        vis[j][j/2*4+1-j]=1;
                    }
                    else
                    {
                        int s=j/(1<<i)*(1<<i),e=j/(1<<i)*(1<<i)+(1<<i);//不难发现第i轮可能与j交手的人一共同拥有(1<<i)个(包括j本身)
                                                                       //因此能够在第i轮时把队伍依照(1<<i)个一组进行分组,接下来就仅仅要找到j的分组
                                                                       //所以s=j/(1<<i)*(1<<i)能够求出可能与j交手的人的最小编号
                                                                       //e=j/(1<<i)*(1<<i)+(1<<i)是最大编号
                        for(int k=s;k<e;k++)
                            if(!vis[j][k])//假设没有交过手
                            {
                                vis[j][k]=1;
                                dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k];
                            }
                    }
                }
            double maxx=-1;
            int win=0;
            for(int i=0;i<people;i++)
            {
                if(dp[n][i]>maxx)
                {
                    maxx=dp[n][i];
                    win=i+1;
                }
            }
            printf("%d
    ",win);
        }
        return 0;
    }
    


    #include<stack>
    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #pragma commment(linker,"/STACK: 102400000 102400000")
    #define lson a,b,l,mid,cur<<1
    #define rson a,b,mid+1,r,cur<<1|1
    using namespace std;
    const double eps=1e-6;
    const int MAXN=(1<<7)+5;
    
    double p[MAXN][MAXN],dp[10][MAXN];
    int n;
    
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
        while(scanf("%d",&n)&&n!=-1)
        {
            int people=1<<n;
            for(int i=0;i<people;i++)
                for(int j=0;j<people;j++)
                    scanf("%lf",&p[i][j]);
            memset(dp,0,sizeof(dp));
            for(int i=0;i<people;i++)
                dp[0][i]=1;
            for(int i=1;i<=n;i++)
                for(int j=0;j<people;j++)
                    for(int k=0;k<people;k++)
                        if(((j>>(i-1))^1)==(k>>(i-1)))//通过二进制来推断在第i轮能否相遇
                            dp[i][j]+=dp[i-1][j]*dp[i-1][k]*p[j][k];
            double maxx=-1;
            int win=0;
            for(int i=0;i<people;i++)
            {
                //printf("%.3lf ",dp[n][i]);
                if(dp[n][i]>maxx)
                {
                    maxx=dp[n][i];
                    win=i+1;
                }
            }
            printf("%d
    ",win);
        }
        return 0;
    }


  • 相关阅读:
    用C#制作PDF文件全攻略
    侦测软件鸟哥linux学习笔记之源代码安装侦测软件
    类模式Java设计模式之十五(桥接模式)类模式
    安装配置Maven入门什么是maven和maven的安装和配置安装配置
    查看表空间oracle rman catalog目录数据库创建过程查看表空间
    产品群体互联网产品设计规划产品群体
    问题修改highcharts 导出图片 .net c#(二)问题修改
    音频播放android4.2音频管理技术音频播放
    重启启动eclipse 中启动Tomcat超时了错误如下:重启启动
    关系建立对于内向、不善于社交的人来说,如何建立人脉?关系建立
  • 原文地址:https://www.cnblogs.com/tlnshuju/p/6952785.html
Copyright © 2011-2022 走看看