访问艺术馆
gallery.pas/c/cpp
【问题描述】
经过数月的精心准备,Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动。艺术馆的结构,
每条走廊要么分叉为两条走廊,要么通向一个展览室。Peer知道每个展室里藏画的数量,并且他精确测量了通
过每条走廊的时间。由于经验老到,他拿下一幅画需要5秒的时间。你的任务是编一个程序,计算在警察赶来前
,他最多能偷到多少幅画。
【输入格式】
第1行是警察赶到的时间,以秒为单位。第2行描述了艺术馆的结构,是一串非负整数,成对地出现:每一
对的第一个数是走过一条走廊的时间,第2个数是它末端的藏画数量:如果第2个数是0那么说明这条走廊分叉为
两条另外的走廊。数据按照深度优先的次序给出,请看样例。
一个展室最多有20幅画。通过每个走廊的时间不超过20秒。艺术馆最多有100个展室。警察赶到的时间在
10分钟以内。
【输出格式】
输出画的数量。
【输入样例】(见下图)
60
7 0 8 0 3 1 14 2 10 0 12 4 6 2
【输出样例】
2
【时间限制】
1s
【空间限制】
64M
//-------------------------------------------------------------------------------------------
分析:f[i,j]表示以i为根的子树偷j幅画所需的最小时间,最后答案即满足f[root,k]<limit的最大的k.
转移时枚举左右子树各偷几幅.
code:
const oo=10000000; maxn=100; maxp=120; var t,p,l,r:array[0..maxn] of longint; f:array[0..maxn,0..maxp] of longint; n,m,lim,i,j:longint; function min(a,b:longint):longint; begin if a>b then exit(b); exit(a); end; procedure build(node,lr:longint); var now:longint; begin inc(n); read(t[n],p[n]); if lr=0 then l[node]:=n else r[node]:=n; now:=n; if p[now]=0 then begin build(now,0); build(now,1); end; end; procedure DP(u:longint); var o,k:longint; begin if u=0 then exit; if (l[u]=0)and(r[u]=0) then begin f[u,0]:=0; for o:=1 to p[u] do f[u,o]:=o*5+t[u]*2; exit; end; DP(l[u]); DP(r[u]); for o:=0 to maxp do for k:=0 to o do f[u,o]:=min(f[u,o],f[l[u],k]+f[r[u],o-k]+t[u]*2); end; begin assign(input,'gallery.in'); reset(input); assign(output,'gallery.out'); rewrite(output); readln(lim); build(1,0); for i:=1 to maxn do for j:=1 to maxp do f[i,j]:=oo; DP(1); for m:=maxp downto 1 do if f[1,m]<lim then break; writeln(m); close(input); close(output); end.