[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
", ansi);
	return 0;
}
原文地址:https://www.cnblogs.com/manziqi/p/9205060.html