boj 452 解码锦标赛【动态规划】(排位赛08_D)

来源:互联网 发布:java字节转为字符串 编辑:程序博客网 时间:2024/05/17 15:35

题目链接:http://code.bupt.edu.cn/problem/p/452/


时间限制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,则认为胜率相等,输出序号最小者。

输入样例

20.0 0.1 0.2 0.30.9 0.0 0.4 0.50.8 0.6 0.0 0.60.7 0.5 0.4 0.020.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

输出样例

24


比赛的赛程规划像是一颗二叉树,但是用动态规划做。

dp[i][j]表示队伍 i 在第 j 场比赛获胜的概率,可得出如下dp方程:

dp[i][j]=dp[i][j-1]*∑(dp[k][j-1]*p[i][k])

  (k的范围判断:连加的数量为2^(j-1),如此只需要知道k的起始值即可,k的起始值可以做j-1次除以2的操作,判断奇偶分别进行+1/-1操作之后再乘以j-1次乘以2的操作得到,不明白的同学可以自己画一个简易图验证一下;每次连加k+1)

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define N 260using namespace std;double p[N][N];int power[]={1,2,4,8,16,32,64,128,256,512};double dp[N][9];int main(){    int n;    while(~scanf("%d",&n)&&n)    {        memset(dp,0,sizeof(dp));        for(int i=0;i<power[n];i++)            for(int j=0;j<power[n];j++)                scanf("%lf",&p[i][j]);        for(int i=0;i<power[n];i+=2)        {            dp[i][1]=p[i][i+1];            dp[i+1][1]=p[i+1][i];        }        for(int j=2;j<=n;j++)        {            for(int i=0;i<power[n];i++)            {                int st,t,temp=i;                for(t=1;t<j;t++)                    temp/=2;                if(temp%2) st=temp-1;                else st=temp+1;                while((t--)-1)                    st*=2;                for(int k=0;k<power[j-1];k++)                {                    dp[i][j]+=dp[st+k][j-1]*p[i][st+k];                }                dp[i][j]*=dp[i][j-1];            }        }        int ans;        double max_p=0;        for(int i=0;i<power[n];i++)        {            if(dp[i][n]>max_p && abs(dp[i][n]-max_p)>=0.001)            {                max_p=dp[i][n];                ans=i;            }        }        printf("%d\n",ans+1);    }    return 0;}


0 0
原创粉丝点击