[NOI导刊] [2010] [提高] 淘汰赛制
NOI导刊 2010 提高 淘汰赛制
题目:
题目描述
淘汰赛制是一种极其残酷的比赛制度。\(2n\)名选手分别标号\(1,2,3,…,2^{n}-1,2^{n}\),他们将要参加\(n\)轮的激烈角逐。每一轮中,将所有参加该轮的选手按标号从小到大排序后,第\(1\)位与第\(2\)位比赛,第\(3\)位与第\(4\)位比赛,第\(5\)位与第\(6\)位比赛……只有每场比赛的胜者才有机会参加下一轮的比赛(不会有平局)。这样,每轮将淘汰一半的选手。\(n\)轮过后,只剩下一名选手,该选手即为最终的冠军。现在已知每位选手分别与其他选手比赛获胜的概率,请你预测一下谁夺冠的概率最大。
输入输出格式
输入格式:
第一行是一个整数\(n(l \leqslant n \leqslant 10)\),表示总轮数。接下来\(2^{n}\)行,每行\(2^{n}\)个整数,第\(i\)行第\(j\)个是\(P_{i j}(0≤P_{i j}≤100,P_{ii}=0,P_{i j}+P_{j i}=100)\),表示第\(i\)号选手与第\(j\)号选手比赛获胜的概率。
输出格式:只有一个整数\(c\),表示夺冠概率最大的选手编号(若有多位选手,输出编号最小者)。
输入输出样例
输入样例#1:
2 0 90 50 50 10 0 10 10 50 90 0 50 50 90 50 0
输出样例#1:
1
说明
\(30%\)的数据满足\(n \leqslant 3\);\(100%\)的数据满足\(n \leqslant 10\)。
题解:
为表达简洁,我还是设几个值吧:
设\(p[i][j]\)为\(j\)号选手第\(i\)轮晋级的概率;\(m[i][j]\)为\(i\)与\(j\)比赛的胜利概率。
分组,每一轮求出有可能与\(i\)进行比赛的选手。设\(l\)与\(r\)为有可能与\(i\)比赛选手的序列的左区间与右区间,\(q\)为当前比赛轮数,求\(sum = \sum_{k = l}^{r} p[q - 1][k] * m[i][k]\),\(p[q][i]\)即为\(p[q - 1][i] * sum\)。
#include <cstdio>
const int MAXN = 1100;
const double EPS = 1e-6;
int m[MAXN][MAXN];
double p[12][MAXN];
int n, tn, ansi;
int main() {
scanf("%d", &n);
tn = 1 << n;
for (int i = 1; i <= tn; ++i)
for (int j = 1; j <= tn; ++j)
scanf("%d", &m[i][j]);
for (int i = 1; i <= tn; ++i) p[0][i] = 1.0; //因为第零轮肯定没有人淘汰,所以均为1.0
for (int i = 1; i <= n; ++i) {
int rnum = 1 << (i - 1);
for (int j = 1; j <= tn; ++j) {
int numt(0), numc(0);
numt = (j - 1) / rnum + 1; //计算i号选手的当前组数
numc = (numt & 1) ? numt + 1 : numt - 1;
int rangex = rnum * numc; double sum(0);
for (int k = rnum * (numc - 1) + 1; k <= rangex; ++k) //得到有可能与其比赛的选手范围
sum = sum + p[i - 1][k] * m[j][k] * 0.01;
p[i][j] = p[i - 1][j] * sum;
}
}
ansi = 1;
for (int i = 2; i <= tn; ++i)
if(p[n][i] - p[n][ansi] > EPS) ansi = i;
printf("%d\n", ansi);
return 0;
}