POJ3071题解(概率dp)

POJ3071题解

题意

给定正整数n,共有2^n支球队,按照二分顺序比赛,给定球队i对球队j的胜率,问哪只球队有最大几率获胜。

笺释

这道题还是很好的体现了动态概率思想。
从最朴素的想法来说,P[球队i获胜]=P[球队i赢第1局]P[球队i赢第2局]…*P[球队i赢第n局]
球队i赢第1局的概率根据数据可直接获得,来考虑球队i赢第j局的概率。
设dp[i][j]为在第i轮球队j获胜的概率。

dp[i][j]+=dp[i-1][j]*dp[i-1][rival[i][j][k]]*P[j][rival[i][j][k]]

其中rival[i][j][k]意为在第i轮球队j的第k个对手,分析可知k=2^i-1,只需要预处理出rival矩阵然后就能顺利进行dp。

完整代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 150
using namespace std;
int rival[8][MAXN][MAXN/2],n;
double P[MAXN][MAXN];
double dp[8][MAXN];
void init(int s,int e,int tn)
{
    if(tn==0)
    {
        return;
    }
    if(s==e)
    {
        return;
    }
    //在第2轮 对手有2种可能性
    //在第tn轮 对手有2^n-1种可能性
    int mid=(s+e)/2;
    //mid定义为中间分开的前面一个
    int m=pow(2,tn-1);
    for(int i=s;i<=mid;i++)
    {
        for(int j=1;j<=m;j++)
        {
            rival[tn][i][j]=mid+j;
           // printf("%d %d %d %d\n",tn,i,j,e/2+j);
        }
    }
    init(s,mid,tn-1);
    for(int i=mid+1;i<=e;i++)
    {
        for(int j=1;j<=m;j++)
        {
            rival[tn][i][j]=s+j-1;
        }
    }
    init(mid+1,e,tn-1);
}
int main()
{
    while(scanf("%d",&n),n!=-1)
    {
        memset(dp,0,sizeof(dp));
        int m=pow(2,n);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%lf",&P[i][j]);
               // printf("%d %d %f\n",i,j,P[i][j]);
            }
        }
        init(1,m,n);
        for(int i=1;i<=m;i++)
        {
           // printf("%d %d %f\n",i,rival[1][i][1],P[i][rival[1][i][1]]);
            dp[1][i]=P[i][rival[1][i][1]];
        }
        for(int i=2;i<=n;i++)
        {
            int l=pow(2,i-1);
            for(int j=1;j<=m;j++)
            {
                for(int k=1;k<=l;k++)
                {
                   dp[i][j]+=dp[i-1][j]*dp[i-1][rival[i][j][k]]*P[j][rival[i][j][k]];
                }
            }
        }
        double ansx=0;
        int ansi=0;
        for(int i=1;i<=m;i++)
        {
            if(dp[n][i]>ansx)
            {
                //printf("%f %d\n",dp[n][i],i);
                ansx=dp[n][i];
                ansi=i;
            }
        }
        printf("%d\n",ansi);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值