2018 CodeM资格赛--第三题:世界杯

题意:给16支球队互相胜利的概率,问每支球队获胜的概率。

题目描述

世界杯就要开始啦!真真正正的战斗从淘汰赛开始,现在我们给出球队之间的胜负概率,来预测每支球队夺冠的可能性。
在接下来的篇幅中,我们将简单介绍淘汰赛阶段的规则。
淘汰赛阶段的90分钟常规时间内(含补时阶段)进球多的球队取胜,如果参赛双方在90分钟内(含补时阶段)无法决出胜负,将进行上下半场各15分钟的加时赛。加时赛阶段,如果两队仍未分出胜负,则通过点球大战决出胜者。也就是说,每场比赛,有且仅有一个队能够晋级到下一轮。
淘汰赛共有16支球队参加(小组赛阶段共分8个小组,每组前两名晋级),对阵安排如下。
1/8决赛
A组第一对阵B组第二=胜者1
B组第一对阵A组第二=胜者2
C组第一对阵D组第二=胜者3
D组第一对阵C组第二=胜者4
E组第一对阵F组第二=胜者5
F组第一对阵E组第二=胜者6
G组第一对阵H组第二=胜者7
H组第一对阵G组第二=胜者8
获胜的8个队进入1/4决赛,即所谓“8强”
1/4决赛
胜者1对阵胜者3=胜者A
胜者2对阵胜者4=胜者B
胜者5对阵胜者7=胜者C
胜者6对阵胜者8=胜者D
1/4决赛的4个获胜队进入“4强”
半决赛
胜者A对阵胜者C
胜者B对阵胜者D
半决赛获胜两队进入决赛,失利的两队争夺三名
决赛获胜的队伍就是最后的冠军!

输入描述:

球队会被以1..16进行标号,其分别表示:
1 A组第一;
2 B组第二;
3 C组第一;
4 D组第二;
5 E组第一;
6 F组第二;
7 G组第一;
8 H组第二;
9 B组第一;
10 A组第二;
11 D组第一;
12 C组第二;
13 F组第一;
14 E组第二;
15 H组第一;
16 G组第二。

数据共有16行,每行16个浮点数,第i行第j列的数Fi,j表示i和j进行比赛时i获胜(包括常规时间获胜、加时赛获胜以及点球大战获胜)的概率。
对于1 <= i, j <= 16 且 i != j, 满足0 <= Fi,j <= 1, Fi,j + Fj,i = 1;
对于1 <= i <= 16, 满足 Fi,i = 0。

输出描述:

输出一行16个浮点数,用空格隔开,分别表示每只球队获得世界杯的概率,结尾无空格。
绝对误差或相对误差在1e-5之内的解会被判为正确。

输入

0.000 0.133 0.210 0.292 0.670 0.270 0.953 0.353 0.328 0.128 0.873 0.082 0.771 0.300 0.405 0.455
0.867 0.000 0.621 0.384 0.934 0.847 0.328 0.488 0.785 0.308 0.158 0.774 0.923 0.261 0.872 0.924
0.790 0.379 0.000 0.335 0.389 0.856 0.344 0.998 0.747 0.895 0.967 0.383 0.576 0.943 0.836 0.537
0.708 0.616 0.665 0.000 0.146 0.362 0.757 0.942 0.596 0.903 0.381 0.281 0.294 0.788 0.804 0.655
0.330 0.066 0.611 0.854 0.000 0.687 0.983 0.217 0.565 0.293 0.256 0.938 0.851 0.487 0.190 0.680
0.730 0.153 0.144 0.638 0.313 0.000 0.832 0.526 0.429 0.707 0.414 0.617 0.925 0.638 0.526 0.545
0.047 0.672 0.656 0.243 0.017 0.168 0.000 0.357 0.125 0.307 0.879 0.551 0.641 0.959 0.981 0.465
0.647 0.512 0.002 0.058 0.783 0.474 0.643 0.000 0.325 0.494 0.893 0.064 0.563 0.429 0.501 0.872
0.672 0.215 0.253 0.404 0.435 0.571 0.875 0.675 0.000 0.940 0.053 0.329 0.232 0.280 0.359 0.474
0.872 0.692 0.105 0.097 0.707 0.293 0.693 0.506 0.060 0.000 0.040 0.776 0.589 0.704 0.018 0.968
0.127 0.842 0.033 0.619 0.744 0.586 0.121 0.107 0.947 0.960 0.000 0.486 0.266 0.662 0.374 0.698
0.918 0.226 0.617 0.719 0.062 0.383 0.449 0.936 0.671 0.224 0.514 0.000 0.821 0.027 0.415 0.227
0.229 0.077 0.424 0.706 0.149 0.075 0.359 0.437 0.768 0.411 0.734 0.179 0.000 0.841 0.409 0.158
0.700 0.739 0.057 0.212 0.513 0.362 0.041 0.571 0.720 0.296 0.338 0.973 0.159 0.000 0.935 0.765
0.595 0.128 0.164 0.196 0.810 0.474 0.019 0.499 0.641 0.982 0.626 0.585 0.591 0.065 0.000 0.761
0.545 0.076 0.463 0.345 0.320 0.455 0.535 0.128 0.526 0.032 0.302 0.773 0.842 0.235 0.239 0.000

输出

0.0080193239 0.1871963989 0.0797523190 0.1233859685 0.0836167329 0.0438390981 0.0079035829 0.0604644891 0.0237087902 0.0050549016 0.1149551151 0.0679247259 0.0511307364 0.0395744604 0.0800843771 0.0233889799

思路分析:仔细看题目可以知道,给出的PK顺序已经是有序的了,就是前面胜利的与临接的后面胜利的队伍打。具体来说:把16支队伍标识成1.....16.

第一轮:1和2打,3和4打,5和6打......15和16打。(这里是输入给出的单个队伍胜利单个队伍)

第二轮:12中胜利的和34中胜利的打,56中胜利的和78胜利的打,910胜利的和11 12胜利的打......。(将1234看作一个大组,那么都减去一个1之后    0123   除以4 都等于 0 。       同理  5678都减一除以4等于1.....依次类推)

第三轮:1234胜利和5678打,9 10 11 12胜利和13 14 15 16胜利的打。(12345678 减一 除以 8 等于0  ....)。

第四轮12345678 和后面八支队伍打,决胜出冠军。

我们可以看到比赛总共打4轮,每轮在一个当前大组内的决出一个胜利者进行下轮  比如12 打34  胜利者进入第三轮。那么我们将1234看作大组,将12 和 34 看作两个小组,这两个小组已经在上一轮决出胜负,1 2 减一 除以 2 是一组,3 4 减一除以2 是一组。

然后说完分组,来说概率。

在一个大组内,比如1234.我们可以分别算出1 2 3 4在一个大组内胜出的概率  记为dp[1.....4][2](第二轮)。  假设1要胜出,那么1要胜利了2 之的概率也就是  dp[1][1](第一轮胜出的概率) ,如果3胜出 那么dp[1][1] * dp[3][1](3在第一轮胜出的概率)*F[1][3](1要胜3的概率)    加上  如果4要胜出的概率 dp[1][1] * dp[4][1](4在第一轮胜出的概率)*F[1][4](1要胜3的概率) 。

一直递推就是答案。

dp[i][j]代表第i支球队在j轮胜出的概率。

总共进行4轮

dp[i][4]就是答案。

代码如下:

#include <stdio.h>
#include <iostream>
#include <string.h>

using namespace std;
const int maxn = 20;
double F[20][20],n;
double dp[20][10];
int main(){
    double a = 0.133*(0.335*0.210 + 0.665*0.292);
    double b = 0.867*(0.335*0.621 + 0.665*0.384);
    double c = 0.335*(0.133*0.790 + 0.867*0.379);
    double d = 0.665*(0.133*0.708 + 0.867*0.616);
    //printf("%.5f\n",a+b+c+d);
    for(int i=1;i<=16;i++){
        for(int j=1;j<=16;j++){
            scanf("%lf",&F[i][j]);
        }
    }
    memset(dp,0,sizeof(0));
    for(int i=1;i<=16;i++){
        if(i%2==1) dp[i][1] = F[i][i+1];
        else dp[i][1] = F[i][i-1];
    }
    for(int i=2;i<=4;i++){
        int sub = 1 << i;
       // printf("%d\n",sub);
        for(int j=1;j<=16;j++){
            for(int k=1;k<=16;k++){
                if((k-1)/sub == (j-1)/sub){
                   // printf("+++++++++++++++++++++++\n");
                    if((k-1)/(sub/2)!=(j-1)/(sub/2)){
                     //   cout<<"---------"<<endl;
                        dp[j][i]+= dp[j][i-1] * dp[k][i-1] * F[j][k];
                    }
                }
            }
        }
    }
    printf("%.10f",dp[1][4]);
    for(int j=2;j<=16;j++){
        printf(" %.10f",dp[j][4]);
    }
    puts("");
    return 0;
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值