I and OI
Past...

访问艺术馆
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.

posted on 2011-08-06 21:14  exponent  阅读(560)  评论(0编辑  收藏  举报