[题目链接:世界杯]
\qquad
牛牛要参加一场程序猿世界杯,一共有
2
n
2^n
2n名选手参加比赛,选手们依次编号从
1
1
1到
2
n
2^n
2n,比赛采用单淘汰制,即第一轮
1
,
2
)
,
(
3
,
4
)
,
⋯
,
(
2
n
−
1
,
2
n
)
(
1,2),(3,4),⋯ ,(2^n−1,2^n)(
1,2),(3,4),⋯ ,(2n−1,2n)(进行比赛,第一轮的决胜者再与相连的选手进行比赛,每轮都会淘汰一半的选手,进行n之后能决出冠军。牛牛的编号为m,但是牛牛知道了各个选手与其他选手比赛时的胜率。牛牛想知道他能夺冠的概率是多少呢,牛牛给你各个选手之间若进行比赛时的胜率,请你告诉牛牛他夺冠可能的概率是多少呢?
思路:
\qquad
这是一个计算概率和问题,题目中规定了比赛的顺序。需要自底向上计算每个人在每轮比赛获胜的概率,进而得到最终获胜的概率。
\qquad
可以使用一个二维数组:
P
[
k
]
[
i
]
\mathrm{P[k][i]}
P[k][i]表示
k
\mathrm{k}
k选手在第
i
\mathrm{i}
i轮比赛获胜的概率,
a
[
i
]
[
j
]
\mathrm{a[i][j]}
a[i][j]表示
i
\mathrm{i}
i选手战胜
j
\mathrm{j}
j选手的概率。
P
[
k
]
[
i
]
\mathrm{P[k][i]}
P[k][i]的计算方法为本轮淘汰赛中
k
\mathrm{k}
k选手战胜对应组中所有选手的概率和。首先确定对应组的选手索引,由
P
[
k
]
[
i
−
1
]
\mathrm{P[k][i-1]}
P[k][i−1]可以得到上一轮中每位选手获胜的概率,则第
i
\mathrm{i}
i轮比赛中
k
\mathrm{k}
k选手获胜的概率为:
P
[
k
]
[
i
]
=
∑
l
P
[
k
]
[
i
−
1
]
∗
a
[
k
]
[
l
]
∗
P
[
l
]
[
i
−
1
]
\mathrm{P[k][i]=\sum_{l}P[k][i - 1] * a[k][l] * P[l][i - 1]}
P[k][i]=l∑P[k][i−1]∗a[k][l]∗P[l][i−1]
代码:
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn = 1500;
double p[maxn][10];
double a[maxn][maxn];
int n,m;
int main()
{
cin >> n >> m;
int num = 1 << n;
for(int i = 0;i < num; ++i)
{
for(int j = 0;j < num; ++j)
{
cin >> a[i][j];
a[i][j] /= 100;
}
}
for(int i = 0;i < num; ++i)
{
p[i][0] = a[i][i ^ 1];
}
// For each layer
for(int i = 1;i < n; ++i)
{
// For each group
int groupSize = 1 << i;
for(int j = 0;j < num; j += groupSize)
{
// Source group
for(int k = j;k < j + groupSize; ++k)
{
p[k][i] = 0;
// Target group
int tag = j / groupSize;
int tarGroup = groupSize;
if(tag & 1)
{
tarGroup *= -1;
}
for(int l = j + tarGroup;l < j + groupSize + tarGroup; ++l)
{
if(l == k) continue;
p[k][i] += p[k][i - 1] * a[k][l] * p[l][i - 1];
}
}
}
}
cout << p[m - 1][n - 1] << endl;
return 0;
}