【问题描述】
淘汰赛制是一种极其残酷的比赛制度。名选手分别标号,,,…,,,他们将要参加轮的激烈角逐。每一轮中,将所有参加该轮的选手按标号从小到大排序后,第位与第位比赛,第位与第位比赛,第位与第位比赛……只有每场比赛的胜者才有机会参加下一轮的比赛(不会有平局)。这样,每轮将淘汰一半的选手。轮过后,只剩下一名选手,该选手即为最终的冠军。
现在已知每位选手分别与其他选手比赛获胜的概率,请你预测一下谁夺冠的概率最大。
【输入文件】
输入文件。第一行是一个整数≤≤,表示总轮数。接下来行,每行个整数,第行第个是≤≤,,,表示第号选手与第号选手比赛获胜的概率。
【输出文件】
输出文件。只有一个整数,表示夺冠概率最大的选手编号(若有多位选手,输出编号最小者)。
【样例输入】
【样例输出】
【数据规模】
的数据满足≤;的数据满足≤。
思路:
设d[i,j]表示第j位选手通过第i轮的概率;P[i,j]表示第i号选手与第j号选手比赛获胜的概率;
状态转移方程:d[i,j] =d [i-l,j]*sum{d[i-l,k]*p[j,k]}(i=l..n,j=1..2n,k为所有可能在第i轮与第j位选手交战的选手编号),边界条件d[0,j]=1。时间复杂度O(n2*2n)。
方程其实还好理解,就是一开始没有想到怎么去求k,看了一位大牛的解题报告后想明白了。
第i轮其实就是每2^i个人中选出一个,而这些人的编号又是相连的,且最小可能编号为(j-1) div (1 shl i)*(1 shl i)+1,因为有边界,要确保都是从上一组2^i+1个人开始的,所以是j-1,还有分左右子树来分析,可能分析得有点乱,画个图区看看就清楚了。下面就是我的ac代码,注释里的是调试输出和那位大牛的写法。
ac程序:
var a:array[0..1024,0..1024] of longint;
f:array[0..10,0..1024] of real;
n,m,i,j,k,x:longint;
sum:real;
begin
assign(input,'elimination.in'); assign(output,'elimination.out');
reset(input); rewrite(output);
readln(n);
m:=1 shl n;
for i:=1 to m do
f[0,i]:=1;
for i:=1 to m do
begin for j:=1 to m do
read(a[i,j]);
readln; end;
for i:=1 to n do
for j:=1 to m do
begin
x:=j-1;
x:=(x div (1 shl i)) * (1 shl i); {writeln(x,' X','j:',j);}
{x:=j;}
{repeat
dec(x);
until x mod (1 shl i)=0; writeln(x); }
if x+1 shl (i-1)>=j then inc(x,1 shl (i-1));
for k:=x+1 to x+1 shl (i-1) do
f[i,j]:=f[i,j]+f[i-1,k]*a[j,k]/100;
f[i,j]:=f[i,j]*f[i-1,j];
end;
{for i:=1 to m do
writeln(f[n,i]);}
sum:=0;
for i:=1 to m do
if f[n,i]>sum then
begin sum:=f[n,i]; x:=i; end;
writeln(x);
close(input); close(output);
end.