暑期个人赛--第八场--D

时间限制 1000 ms  内存限制 65536 KB

题目描述

明光村迎来了一年一度的盛世——解码锦标赛,有 2^N 次个队伍从世界各村赶来参与比赛,编号为 1 - 2^N。赛制为每一轮晋级一半队伍,按序号大小两两比赛,淘汰弱者。一轮结束后,所有的胜者进入下一轮,依旧是按顺序两两比赛。比如第一轮就是 1 vs 2, 3 vs 4 ... 2^N - 1 vs 2^N。在一旁围观的 Mays 学姐告诉你,N次比赛后的胜者是唯一的。现在你拿到了一份各个参赛队伍的对抗胜率表 win,为 2^N * 2^N 的矩阵, win[i][j] 为一位小数,代表i胜j的概率。 

你能告诉 Mays 学姐最有可能获得世界冠军的是那支队伍吗?

输入格式

多组数据。每组第一行为 N ,N <= 8,接下来 N 行 N 列为对抗胜率矩阵。 保证 win[i][j] + win[j][i] = 1 (i != j)。 以 N=0 结束输入。 

输出格式

对每组数据,输出胜率最大的队伍的序号。如果最大的两个概率相差不到 0.001,则认为胜率相等,输出序号最小者。

输入样例

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
2
0.0 0.8 0.1 0.4 
0.2 0.0 0.2 0.6 
0.9 0.8 0.0 0.3 
0.6 0.4 0.7 0.0 
0

输出样例

2
4


赛中提交:NULL

赛后AC:Y


题目大意:

有2的n次方个人伍参加比赛,采用两两淘汰晋级制(七龙珠的武道大会),求最后胜率最大的人。


思路:

也就是说要决出最终胜者,一个人一共要打n场比赛。

很明显这是一个dfs的题目,在一个完美二叉树上做递归运算,再加上记忆化搜索优化时间

递推式:

dp[i][j]表示第i号选手在第j次比赛中获胜的概率。

p[i][j]表示第i号选手击败第j号选手的概率

dp[i][j]=dp[i][j-1]*segma(dp[k][j-1]*p[i][k]) (k为i在第n次比赛中的兄弟树的所有最末尾的孙子序号)



下面是AC代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 500

using namespace std;
double dp[maxn][10],p[maxn][maxn];
int n;
const double eps=0.001;

double dfs(int num,int level)
{
    if(dp[num][level]!=-1){
        //printf("(%d %d):%lf \n",num,level,dp[num][level]);
        return dp[num][level];
    }
    else{
        double sum=0;
        int tmp1=pow(2,level-1);
        if(((num-1)/tmp1)%2==0){
            for(int i=((num-1)/tmp1+1)*tmp1;i<((num-1)/tmp1+2)*tmp1;i+=1){
                sum+=dfs(i+1,level-1)*p[num][i+1];
            }
        }
        else{
            for(int i=((num-1)/tmp1-1)*tmp1;i<((num-1)/tmp1)*tmp1;i+=1){
                sum+=dfs(i+1,level-1)*p[num][i+1];
            }
        }
        //printf("aaaa%lf\n",sum);
        return dp[num][level]=dfs(num,level-1)*sum;
    }
}

int main()
{
    while(1){
        scanf("%d",&n);
        if(!n){
            break;
        }
        int N=pow(2,n);
        for(int i=1;i<=N;i+=1){
            for(int j=1;j<=n;j+=1){
                dp[i][j]=-1.0;
            }
        }
        for(int i=1;i<=N;i+=1){
            for(int j=1;j<=N;j+=1){
                scanf("%lf",&p[i][j]);
                if((i%2==0&&j==i-1)||(j%2==0&&i==j-1)){
                    dp[i][1]=p[i][j];
                }
            }
        }

        double maxp=0,tmp;
        int ans=0;
        for(int i=1;i<=N;i+=1){
            tmp=dfs(i,n);
            //printf("--%d %lf\n",i,tmp);
            if(tmp>maxp+eps){
                maxp=tmp;
                ans=i;
            }
        }

        printf("%d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值