【POJ3071】Football

来源:互联网 发布:java支付宝开发流程 编辑:程序博客网 时间:2024/04/29 03:58

题目链接:传送门
题解
求概率正着递推即可
f[i][j]表示第i轮中j队伍获胜的概率,我们发现如果f[i][j]>0,即i队伍在第j轮中获胜,那么必须满足f[i1][j]>0,即i队伍在第j1轮中获胜,而且他的对手必须也在前一轮获胜,发现这其实是一个全概率公式
f[i][j]=(f[i1][j]×f[i1][k]×p[j][k]),其中p[j][k]代表p战胜k的概率,然后关键是如何求k的范围
我们把比赛流程图画出来,发现它其实是一个二叉树的结构
它的对手应该是它父节点另一棵子树的叶节点的任意一个
我们把所有选手从零开始编号,发现这个东西其实在二进制下是很好判断的(很难具体说出来,自己看代码模拟就好)
貌似我被精度卡了好久hhh
说出来你们可能不信,我把27算成64,空间开小,卡了一天…

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int N=130;double f[N][N],p[N][N];int n,tot,ans;int main(){    while(~scanf("%d",&n)&&n!=-1)    {        tot=(1<<n);        for(int i=0;i<tot;i++)            for(int j=0;j<tot;j++)            scanf("%lf",&p[i][j]);        for(int i=0;i<tot;i++) f[0][i]=1;        for(int i=1;i<=n;i++)            for(int j=0;j<tot;j++)            {                int h=(j/(1<<(i-1)))^1;                int l=h*(1<<(i-1));                int r=l+(1<<(i-1))-1;                f[i][j]=0;                for(int k=l;k<=r;k++)                    f[i][j]+=f[i-1][k]*p[j][k]*f[i-1][j];            }        ans=0;        for(int i=1;i<tot;i++)            if(f[n][i]>f[n][ans]) ans=i;        printf("%d\n",ans+1);    }    return 0;}
原创粉丝点击