题目描述
奥运物流 【问题描述】 2008 北京奥运会即将开幕, 举国上下都在为这一盛事做好准备。 为了高效率、 成功地举办奥运会,对物流系统进行规划是必不可少的。 物流系统由若干物流基站组成,以 1...N 进行编号。每个物流基站 i 都有且 仅有一个后继基站 Si,而可以有多个前驱基站。基站 i 中需要继续运输的物资都 将被运往后继基站 Si,显然一个物流基站的后继基站不能是其本身。编号为 1 的 从任何物流基站都可将物资运往控制基站。 注意控制基 物流基站称为控制基站, 站也有后继基站,以便在需要时进行物资的流通。在物流系统中,高可靠性与低 成本是主要设计目。对于基站 i,我们定义其“可靠性” R (i ) 如下: 设物流基站 i 有 w 个前驱基站 P1, P2 ,Pw ,即这些基站以 i 为后继基站,则基站 i 的可靠性 R(i)满足下式:w R(i ) = Ci + k ∑ R( Pj )j =1 其中 Ci 和 k 都是常实数且恒为正,且有 k 小于 1。 整个系统的可靠性与控制基站的可靠性正相关, 我们的目标是通过修改物流系统,即更改某些基站的后继基站,使得控制基站的可靠性 R(1)尽量大。但由于经费限制,最多只能修改 m 个基站的后继基站,并且,控制基站的后继基站不可被修改。因而我们所面临的问题就是,如何修改不超过 m 个基站的后继,使 得控制基站的可靠性 R(1)最大化。 【输入格式】 输入文件 trans.in 第一行包含两个整数与一个实数,N, m, k。其中 N 表示基 站数目,m 表示最多可修改的后继基站数目,k 分别为可靠性定义中的常数。 第二行包含 N 个整数,分别是 S1, S2...SN,即每一个基站的后继基站编号。 第三行包含 N 个正实数,分别是 C1, C2...CN,为可靠性定义中的常数。 【输出格式】 输出文件 trans.out 仅包含一个实数,为可得到的最大 R(1)。精确到小数点两 位。 【输入样例】 4 1 0.5 2313 10.0 10.0 10.0 10.0 【输出样例】 30.00 【样例说明】 原有物流系统如左图所示,4 个物流基站的可靠性依次为 22.8571,21.4286, 25.7143,10。 最优方案为将 2 号基站的后继基站改为 1 号,如右图所示。 此时 4 个基站 的可靠性依次为 30,25,15,10。 【数据规模和约定】 本题的数据,具有如下分布: 测试数据编号 N M 1 ≤6 ≤6 2 ≤ 12 ≤ 12 3 ≤ 60 0 4 ≤ 60 1 5 ≤ 60 N-2 6~10 ≤ 60 ≤ 60 对于所有的数据,满足 m ≤ N ≤ 60,Ci ≤ 106,0.3 ≤ k < 1,请使用双精度实 数,无需考虑由此带来的误差。
题解
解法1:贪心
1 (* 2 *Problem: NOI2008 奥运物流 3 *Author : Chen Yang 4 *Time : 2012.5.20 5 *State : 70分 6 *Memo : 贪心 7 *) 8 program trans; 9 type 10 ty1=^ty2; 11 ty2=record 12 x:longint; 13 next:ty1; 14 end; 15 var 16 n,m,i:longint; 17 k,ans:extended; 18 father:array[0..100] of longint; 19 c,r:array[0..100] of extended; 20 get:array[0..100] of boolean; 21 first:array[0..100] of ty1; 22 //===================== 23 procedure insert(x,y:longint); 24 var 25 p:ty1; 26 begin 27 new(p); 28 p^.x:=y; 29 p^.next:=first[x]; 30 first[x]:=p; 31 end; 32 //===================== 33 procedure find(i:longint; kx:extended); 34 var 35 p:ty1; 36 x:extended; 37 son:longint; 38 begin 39 p:=first[i]; x:=0; son:=0; 40 while p<>nil do 41 begin 42 if not get[p^.x] then 43 begin 44 find(p^.x,kx); 45 x:=x+r[p^.x]; 46 end else son:=p^.x; 47 p:=p^.next; 48 end; 49 if not get[i] then r[i]:=x*k+c[i] else ans:=ans+c[i]*kx+x*kx*k; 50 if son>0 then find(son,kx*k); 51 end; 52 //===================== 53 procedure work; 54 var 55 i,t:longint; 56 kx:extended; 57 begin 58 fillchar(first,sizeof(first),0); 59 fillchar(get,sizeof(get),false); 60 for i:=2 to n do insert(father[i],i); 61 ans:=0; t:=0; 62 i:=1; 63 while father[i]<>1 do 64 begin 65 inc(t); 66 get[i]:=true; 67 i:=father[i]; 68 end; 69 get[i]:=true; inc(t); 70 find(1,1); 71 kx:=1; 72 for i:=1 to t do kx:=kx*k; 73 ans:=ans/(1-kx); 74 end; 75 //===================== 76 procedure main; 77 var 78 i,t,k,j:longint; 79 begin 80 work; r[1]:=ans; 81 if m=0 then writeln(ans:0:2) else 82 if m=n-2 then 83 begin 84 for i:=2 to n do father[i]:=1; 85 work; 86 writeln(ans:0:2); 87 end else 88 begin 89 for j:=1 to m do 90 begin 91 k:=0; 92 for i:=2 to n do 93 if father[i]<>1 then 94 begin 95 t:=father[i]; father[i]:=1; 96 work; 97 if r[1]<ans then begin r[1]:=ans; k:=i; end; 98 father[i]:=t; 99 end; 100 father[k]:=1; 101 end; 102 writeln(r[1]:0:2); 103 end; 104 end; 105 //===================== 106 begin 107 assign(input,'trans.in'); reset(input); 108 assign(output,'trans.out'); rewrite(output); 109 read(n,m,k); 110 for i:=1 to n do read(father[i]); 111 for i:=1 to n do read(c[i]); 112 main; 113 close(input); close(output); 114 end.
解法2:树形DP
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.