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);
}
}