题目描述
赛程安排 【问题描述】 随着奥运的来临,同学们对体育的热情日益高涨。在 NOI2008 来临之际, 学校正在策划组织一场乒乓球赛。小 Z 作为一名狂热的乒乓球爱好者,这正是 他大展身手的好机会,于是他摩拳擦掌,积极报名参赛。 本次乒乓球赛采取淘汰赛制,获胜者晋级。恰好有 n (n 是 2 的整数次幂,不 妨设 n = 2k)个同学报名参加, 因此第一轮后就会有 2k-1 个同学惨遭淘汰, 另外 2k-1 个同学晋级下一轮;第二轮后有 2k-2 名同学晋级下一轮,... 依次类推,直到 k 轮后决出冠亚军: 具体的, 每个人都有一个 1~n 的初始编号, 其中小 Z 编号为 1, 所有同学的编号都不同, 他们将被分配到 n 个位置中,然后按照类似下图的赛程 进行比赛: 位置 1 位置 2 位置 3 位置 4 位置 5 位置 6 位置 7 位置 8 位置 1 和位置 2 的 位置 3 和位置 4 的 位置 5 和位置 6 的 位置 7 和位置 8 的 胜者 胜者 胜者 胜者 位置 1234 中的胜者 位置 5678 的胜者 冠军 n=8 时比赛的赛程表 为了吸引更多的同学参加比赛,本次比赛的奖金非常丰厚。在第 i 轮被淘汰 的选手将得到奖金 ai 元, 而冠军将获得最高奖金 ak+1 元。显然奖金应满足 a1 < a2 < ... < ak+1. 在正式比赛前的热身赛中,小 Z 连连败北。经过认真分析之后,他发现主要 的失败原因不是他的球技问题, 而是赢他的这几个同学在球风上刚好对他构成相 克的关系,所以一经交手,他自然败阵。小 Z 思索:如果在正式比赛中能够避 开这几位同学,该有多好啊! 假设已知选手两两之间交手的胜率,即选手 A 战胜选手 B 的概率为 PA,B (保 证 PA,B + PB,A=1)。于是小 Z 希望能够通过确定比赛的对阵形势(重新给每个选手 安排位置) 从而能够使得他获得尽可能多的奖金。 , 你能帮助小 Z 安排一个方案, 使得他这场比赛期望获得的奖金最高么? 【输入格式】 这是一道提交答案型试题,所有的输入文件 match*.in 已在相应目录下。 输入文件 match*.in 第一行包含一个正整数 n,表示参赛的总人数,数据保 证存在非负整数 k,满足 2k = n。 接下来 n 行, 每行有 n 个 0 到 1 间的实数 Pi,j,, 表示编号为 i 的选手战胜编号 为 j 的选手的概率,每个实数精确到小数点后两位。特别注意 Pi,i = 0.00。 接下来 k+1 行, 每行一个整数分别为晋级各轮不同的奖金, i 行的数为 ai。 【输出格式】 输出文件 match*.out 包括 n 行,第 i 行的数表示位于第 i 个位置的同学的编 号,要求小 Z 的编号一定位于第 1 个位置。 【输入样例】 4 0.00 0.70 0.60 0.80 0.30 0.00 0.60 0.40 0.40 0.40 0.00 0.70 0.20 0.60 0.30 0.00 1 2 3 【输出样例】 1 4 2 3 【样例说明】 第一轮比赛过后,编号为 1 的选手(小 Z)晋级的概率为 80%,编号为 2 的选 手晋级的概率为 60%,编号为 3 的选手晋级的概率为 40%,编号为 4 的选手晋 级的概率为 20%。 第二轮(决赛) ,编号为 1 的选手(小 Z)前两轮均获胜的概率为 80% * (60%*70% + 40%*60% ) = 52.8%,因此, 小 Z 在第一轮失败的概率 P1=1-0.8=0.2, 第一轮胜出但第二轮败北的概率 P2=0.8-0.528=0.272, 获得冠军的概率 P3=0.528。 从而,期望奖金为 0.2*1 + (0.8-0.528)*2 + 0.528*3 = 2.328。 【如何测试你的输出】 我们提供 match_check 这个工具来测试你的输出文件是否可接受。 使用这 个工具的测试方法是在终端中使用命令: ./match_check 测试数据编号 例如:./match_check 10 表示测试你的 match10.out 是否合法。 调用这个程序后,match_check将根据你得到的输出文件给出测试的结果, 其中包括: 非法退出: Format error: Not a permutation: 未知错误; 输出文件格式错误; 输出文件不是一个1~n的排列; OK.Your answer is xxx:输出文件可以被接受,xxx为对应的期望奖金。 【评分方法】 每个测试点单独评分。 对于每一个测试点,如果你的输出文件不合法,如文件格式错误、输出解不 符合要求等,该测试点得 0 分。否则如果你的输出的期望奖金为 your_ans,参考 期望奖金为 our_ans,我们还设有一个用于评分的参数 d,你在该测试点中的得 分如下: 如果 your_ans > our_ans,得 12 分。 如果 your_ans < our_ans*d,得 1 分。 否则得分为: ⎢ your _ ans − our _ ans * d ⎥ ---------------------------------------- +2 ⎢ our _ ans − our _ ans * d *8⎥ 【提示】 “数学期望” 数学期望是随机变量最基本的数字特征之一。它反映随机变量平均取值的大 小,又称期望或均值。它是简单算术平均的一种推广。例如某城市有 10 万个家 庭,没有孩子的家庭有 1000 个,有一个孩子的家庭有 9 万个,有两个孩子的家 庭有 6000 个,有 3 个孩子的家庭有 3000 个,则该城市中任一个家庭中孩子的数 目是一个随机变量,它可取值 0,1,2,3,其中取 0 的概率为 0.01,取 1 的概 率为 0.9, 2 的概率为 0.06, 3 的概率为 0.03, 取 取 它的数学期望为 0×0.01+1×0.9 +2×0.06+3×0.03 等于 1.11,即此城市一个家庭平均有小孩 1.11 个。 本题中期望值的计算: 假设小 Z 在第一轮被打败的概率为 P1, 第一轮胜利且 在第二轮被打败的概率为 P2, 前两轮胜利且在第三轮被打败的概率为 P3......, 那么小 Z 的期望奖金为: P1 * a1 + P2 * a2 + ...+ Pk+1 * ak+1 【特别提示】 请妥善保存输入文件*.in 和你的输出*.out,及时备份,以免误删。
解法1:爬山法
1 (* 2 *Problem: NOI2008 赛程安排 3 *Author : Chen Yang 4 *Time : 2012.5.22 5 *State : 81分 6 *Memo : 爬山法、调用外部程序 7 *) 8 program match; 9 uses unix; 10 const climb=20; 11 change=15000; 12 chance=10000000; 13 x='10'; 14 var 15 n,i:longint; 16 best:extended; 17 get:array[0..128] of boolean; 18 a,ans,this:array[0..128] of longint; 19 //================= 20 procedure outit; 21 begin 22 assign(output,'tmp'); rewrite(output); 23 writeln(best:0:2); 24 for i:=1 to n do writeln(ans[i]); 25 close(output); 26 end; 27 //================= 28 procedure init; 29 var 30 i,t:longint; 31 begin 32 fillchar(get,sizeof(get),false); 33 a[1]:=1; get[1]:=true; 34 for i:=2 to n do 35 begin 36 t:=random(n)+1; 37 while get[t] do t:=random(n)+1; 38 get[t]:=true; 39 a[i]:=t; 40 end; 41 end; 42 //================= 43 function calc:extended; 44 var 45 i:longint; 46 s:string; 47 begin 48 assign(output,'match'+x+'.out'); rewrite(output); 49 for i:=1 to n do writeln(a[i]); 50 close(output); 51 shell('./match_check '+x+' > now.txt'); 52 assign(input,'now.txt'); reset(input); 53 readln(s); 54 close(input); 55 delete(s,1,19); 56 delete(s,length(s),1); 57 val(s,calc,i); 58 end; 59 //================= 60 procedure main; 61 var 62 i,t,k,x,y:longint; 63 now,tmp:extended; 64 begin 65 best:=0; 66 for i:=1 to climb do 67 begin 68 init; 69 t:=0; now:=calc; this:=a; 70 while t<change do 71 begin 72 repeat 73 x:=random(n-1)+2; y:=random(n-1)+2; 74 until x<>y; 75 k:=a[x]; a[x]:=a[y]; a[y]:=k; 76 tmp:=calc; 77 if tmp>now then 78 begin 79 now:=tmp; 80 this:=a; 81 t:=0; 82 end else 83 begin 84 if random(chance)>t/35 then 85 begin 86 k:=a[x]; a[x]:=a[y]; a[y]:=k; 87 end; 88 inc(t); 89 end; 90 end; 91 if now>best then 92 begin 93 ans:=this; best:=now; 94 outit; 95 end; 96 end; 97 end; 98 //================= 99 begin 100 randomize; 101 assign(input,'match'+x+'.in'); reset(input); 102 read(n); close(input); 103 main; 104 end.
解法2:模拟退火
1 (* 2 *Problem: NOI2008 赛程安排 3 *Author : Chen Yang 4 *Time : 2012.5.23 9:00 am 5 *State : 84分 6 *Memo : 模拟退火、调用外部程序 7 *) 8 program match; 9 uses unix; 10 const x='7'; 11 dt=0.99996; 12 ct=3500; 13 zero=1e-6; 14 var 15 n,i:longint; 16 best:extended; 17 a:array[0..256] of longint; 18 //============== 19 procedure init; 20 var 21 i:longint; 22 begin 23 assign(input,'tmp'); reset(input); 24 read(best); 25 for i:=1 to n do read(a[i]); 26 close(input); 27 end; 28 //============== 29 procedure outit; 30 var 31 i:longint; 32 begin 33 assign(output,'tmp'); rewrite(output); 34 writeln(best:0:15); 35 for i:=1 to n do writeln(a[i]); 36 close(output); 37 end; 38 //============== 39 function calc:extended; 40 var 41 i:longint; 42 s:string; 43 begin 44 assign(output,'match'+x+'.out'); rewrite(output); 45 for i:=1 to n do writeln(a[i]); 46 close(output); 47 shell('./match_check '+x+' > now.txt'); 48 assign(input,'now.txt'); reset(input); 49 readln(s); 50 close(input); 51 delete(s,1,19); 52 delete(s,length(s),1); 53 val(s,calc,i); 54 end; 55 //============== 56 procedure main; 57 var 58 x,y,k:longint; 59 tmp,t,last:extended; 60 begin 61 t:=ct; last:=0; 62 while t>100 do 63 begin 64 repeat 65 x:=random(n-1)+2; y:=random(n-1)+2; 66 until x<>y; 67 k:=a[x]; a[x]:=a[y]; a[y]:=k; 68 tmp:=calc; 69 if tmp>last-zero then 70 begin 71 last:=tmp; 72 if tmp>best then 73 begin 74 best:=tmp; 75 outit; 76 end; 77 end else 78 if random()>exp((tmp-last)/t) then 79 begin 80 k:=a[x]; a[x]:=a[y]; a[y]:=k; 81 end else last:=tmp; 82 t:=t*dt; 83 end; 84 end; 85 //============== 86 begin 87 for i:=1 to 10 do 88 begin 89 randomize; 90 assign(input,'match'+x+'.in'); reset(input); 91 read(n); 92 close(input); 93 init; 94 main; 95 end; 96 end.
1 (* 2 *Problem: NOI2008 奥运物流 3 *Author : Chen Yang 4 *Time : 2012.5.20 5 *State : AC 6 *Memo : 树形DP,多重背包 7 *) 8 program trans; 9 uses math; 10 const maxn=65; 11 var 12 n,m,i,len:longint; 13 k,ans:extended; 14 fa:array[0..maxn] of longint; 15 c,kk,ff:array[0..maxn] of extended; 16 f,g:array[0..maxn,0..maxn,0..maxn] of extended; 17 //================== 18 procedure find(x,d:longint); 19 var 20 i,j,k,l:longint; 21 begin 22 for i:=2 to n do if fa[i]=x then find(i,d+1); 23 for k:=min(2,d) to d do 24 begin 25 for i:=0 to m do ff[i]:=0; 26 for i:=2 to n do if fa[i]=x then 27 for j:=m downto 0 do 28 for l:=j downto 0 do 29 if ff[j]<ff[l]+g[i,j-l,k] then ff[j]:=ff[l]+g[i,j-l,k]; 30 for i:=0 to m do f[x,i,k]:=ff[i]+kk[k]*c[x]; 31 end; 32 if d<>1 then 33 begin 34 for i:=0 to m do ff[i]:=0; 35 for i:=2 to n do if fa[i]=x then 36 for j:=m downto 0 do 37 for l:=j downto 0 do 38 if ff[j]<ff[l]+g[i,j-l,1] then ff[j]:=ff[l]+g[i,j-l,1]; 39 for i:=1 to m do f[x,i,1]:=ff[i-1]+kk[1]*c[x]; 40 end; 41 for j:=0 to m do 42 for k:=0 to d-1 do 43 if f[x,j,k+1]>f[x,j,1] then g[x,j,k]:=f[x,j,k+1] else g[x,j,k]:=f[x,j,1]; 44 end; 45 //================== 46 procedure work(father:longint); 47 var 48 i,j,k:longint; 49 t:extended; 50 begin 51 fillchar(f,sizeof(f),0); 52 fillchar(g,sizeof(g),0); 53 for i:=2 to n do if fa[i]=1 then find(i,1); 54 for i:=0 to m do ff[i]:=0; 55 for i:=2 to n do if fa[i]=1 then 56 for j:=m downto 0 do 57 for k:=j downto 0 do 58 if ff[j]<ff[k]+f[i,j-k,1] then 59 ff[j]:=ff[k]+f[i,j-k,1]; 60 t:=0; 61 for i:=0 to m-1 do 62 if t<ff[i] then t:=ff[i]; 63 if (father=1)and(ff[m]>t) then t:=ff[m]; 64 t:=(t+c[1])/(1-kk[len]); 65 if ans<t then ans:=t; 66 end; 67 //================== 68 procedure main; 69 var 70 i,t:longint; 71 begin 72 kk[0]:=1; for i:=1 to n do kk[i]:=kk[i-1]*k; 73 i:=fa[1]; len:=1; 74 while i<>1 do 75 begin 76 inc(len); t:=fa[i]; fa[i]:=1; 77 work(t); 78 fa[i]:=t; i:=t; 79 end; 80 writeln(ans:0:2); 81 end; 82 //================== 83 begin 84 assign(input,'trans.in'); reset(input); 85 assign(output,'trans.out'); rewrite(output); 86 read(n,m,k); 87 for i:=1 to n do read(fa[i]); 88 for i:=1 to n do read(c[i]); 89 main; 90 close(input); close(output); 91 end.