一、树形dp(1)访问艺术馆

来源:互联网 发布:淘宝秋装什么时候上架 编辑:程序博客网 时间:2024/04/30 15:47
1访问艺术馆
源程序名 gallery.???( pas, c, cpp) 可执行文件名 gallery.exe
输入文件名 gallery.in 输出文件名 gallery.out
【问题描述】
经过数月的精心准备, Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动。
艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室。 Peer 知道每个展室里
藏画的数量,并且他精确测量了通过每条走廊的时间。由于经验老到,他拿下一幅画需要 5
秒的时间。你的任务是编一个程序,计算在警察赶来之前,他最多能偷到多少幅画。
【输入】
第 1 行是警察赶到的时间,以 s 为单位。第 2 行描述了艺术馆的结构,是一串非负整数,
成对地出现:每一对的第一个数是走过一条走廊的时间,第 2 个数是它末端的藏画数量;如
果第 2 个数是 0,那么说明这条走廊分叉为两条另外的走廊。数据按照深度优先的次序给出,
请看样例。
一个展室最多有 20 幅画。通过每个走廊的时间不超过 20s。艺术馆最多有 100 个展室。
警察赶到的时间在 10min 以内。
【输出】
输出偷到的画的数量。
【样例输入】
gallery.in
60
7 0 8 0 3 1 14 2 10 0 12 4 6 2
【样例输出】
gallery.out

2


分析:

树形动归+背包


代码:
var
  f:array [1..200,0..600] of longint;
  a,c:array [1..200] of longint;
  lian:array [1..200,1..2] of longint;
  i,j,m,n,k,t,time,ans:longint;


procedure dfs(i:longint);
begin
  read(c[m],a[m]);
  c[m]:=c[m]*2;
  if a[m]=0 then
  begin
    inc(m);
    lian[i,1]:=m;
    dfs(m);
    inc(m);
    lian[i,2]:=m;
    dfs(m);
  end;
end;


procedure dp(i:longint);
var
  j,k,t,s:longint;
begin
  if a[i]<>0 then
  for j:=1 to a[i] do
  f[i,c[i]+j*5]:=j else
  begin
    for k:=1 to 2 do
    dp(lian[i,k]);
    for k:=1 to 2 do //背包,分给每个子节点t的花费,父节点j的花费
      for j:=time downto c[lian[i,k]]+c[i] do
        for t:=c[lian[i,k]] to j-c[i] do
        if f[i,j]<f[i,j-t]+f[lian[i,k],t] then
        f[i,j]:=f[i,j-t]+f[lian[i,k],t];
  end;
end;


begin
  assign(input,'gallery.in');
  assign(output,'gallery.out');
  reset(input);
  rewrite(output);


  read(time);
  m:=1;
  dfs(1);//递归读入
  dp(1);
  for i:=1 to time do
  if ans<f[1,i] then ans:=f[1,i];
  writeln(ans);


  close(input);
  close(output);
end.




0 0
原创粉丝点击