题意:
给一个n,有1<<n个人进行比赛,对于一个人i,给给出所有的Pij,0<=j<1<<n,Pij表示i战胜j的概率,问谁获得冠军的概率最大。
思路:
这题难度在于cooding,思路比较好想。
我的做法是定义一个b[i][j]的数组,表示第j个人进入到第i轮的概率转移方程为: b[i][j]=b[i-1][j]*(a[i][k]*b[i-1][k]+a[i][k+1]*b[i-1][k+1]......)(k,k+1,k+2...为所有本轮可能面临的选手,比较难处理),最后找到第n-1轮中概率最大那个输出下标既是获得冠军概率最大的那个了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=256;
double a[maxn][maxn];
double b[10][maxn];
double sum;
int main()
{
int n;
while(~scanf("%d", &n))
{
if(n==-1)break;
sum=0;
int m=1<<n;
int i, j, k, e;
for(i=0; i<m; i++)
{
for(j=0; j<m; j++)
{
scanf("%lf", &a[i][j]);
}
}
for(i=0; i<m; i++)
{
if(i%2)b[0][i]=a[i][i-1];
else b[0][i]=a[i][i+1];
}
for(i=1; i<n; i++)
{
for(k=0; k<(1<<n)-1; k+=(1<<(i+1))) //枚举需要进行比赛的区间
{
double sum=0;
for(j=k; j<k+(1<<(i)); j++) //枚举需要计算的选手
{
sum=0;
for(e=k+(1<<(i)); e<k+2*(1<<(i)); e++) //枚举每个选手的可能对手
{
sum+=a[j][e]*b[i-1][e];
}
b[i][j]=sum*b[i-1][j];
}
for(j=k+(1<<(i))+(1<<(i))-1; j>=k+(1<<(i)); j--)
{
sum=0;
for(e=k; e<k+(1<<(i)); e++)
{
sum+=a[j][e]*b[i-1][e];
}
b[i][j]=sum*b[i-1][j];
}
}
}
int maxi=0;
for(i=0; i<m; i++)
{
// printf("%.3lf ", b[n-1][i]);
if(b[n-1][i]>b[n-1][maxi])
{
maxi=i;
}
}
printf("%d\n", maxi+1);
}
return 0;
}