poj 2486 Apple Tree 树形DP

题意:Wshxzt从根节点1开始在苹果树上游历,树上的每个节点都会存在apple[i]个苹果,从一个节点到它的邻节点耗费步数1。现在Wshxzt可以步行step步,求她可以得到的最大苹果数量。

分析:很明显的树形DP。用f[i,j]表示从第i个节点开始走j步最多能吃到多少苹果。然后……然后你就会惊奇地发现你居然不会写,因为主角是可以走回头路的,所以最后是否会回到点i对后面的状态都会有影响,于是就再加多一维:f[i,j,0]表示从第i个节点开始走j步且不会到点i最多能吃到多少苹果,f[i,j,1]表示从第i个节点开始走j步且最后回到点i最多能吃到少苹果(打死宝宝了)。然后接着往下分析:假设y为i的儿子,k为在y为根的树上走k步。若不回到点i,则f[i,j,0]=max{f[y,k,0]+f[i,j-k-1,1],f[y,k,1]+f[i,j-k-2,0]},也就是分最后是否会停留在以y为根的树内。若回到点i,则f[i,j,1]=max{f[y,k,1]+f[i,j-k-2,1]}。

一开始打完之后发现无论跟别人的标程如何相似就是TLE,后来在绝望之前把数组改小了一点(一开始开打了10倍),本想交一下保存就好了,结果一不小心就A了……而且时间还蛮短的……这论证了程序所占空间和耗费的时间是成正比的。

整个人都不好了……

代码:

var
  n,m,i,x,y:longint;
  apple:array[1..100] of longint;
  f:array[1..100,0..200,0..1] of longint;
  a:array[1..100,0..200] of longint;

procedure dfs(x,z:longint);
var
  i,j,k:longint;
begin
  for i:=1 to a[x,0] do
    if a[x,i]<>z then dfs(a[x,i],x);
  for i:=0 to m do
  begin
    f[x,i,0]:=apple[x];
    f[x,i,1]:=apple[x];
  end;
  for i:=1 to a[x,0] do
  begin
    if a[x,i]=z then continue;
    for j:=m downto 0 do
      for k:=0 to j-1 do
      begin
        if f[a[x,i],k,0]+f[x,j-k-1,1]>f[x,j,0] then
          f[x,j,0]:=f[a[x,i],k,0]+f[x,j-k-1,1];

        if j-k-2>=0 then
        begin
          if f[a[x,i],k,1]+f[x,j-k-2,0]>f[x,j,0] then
            f[x,j,0]:=f[a[x,i],k,1]+f[x,j-k-2,0];

          if f[a[x,i],k,1]+f[x,j-k-2,1]>f[x,j,1] then
            f[x,j,1]:=f[a[x,i],k,1]+f[x,j-k-2,1];
        end;
      end;
  end;
end;

begin
  while not eof do
  begin
    readln(n,m);
    for i:=1 to n do
      read(apple[i]);
    fillchar(a,sizeof(a),0);
    for i:=1 to n-1 do
    begin
      readln(x,y);
      inc(a[x,0]);
      a[x,a[x,0]]:=y;
      inc(a[y,0]);
      a[y,a[y,0]]:=x;
    end;
    fillchar(f,sizeof(f),0);
    dfs(1,0);
    if f[1,m,1]>f[1,m,0]
      then writeln(f[1,m,1])
      else writeln(f[1,m,0]);
  end;
end.


你可能感兴趣的:(poj 2486 Apple Tree 树形DP)