SSL 1565 将功补过 树形dp

题意:有一棵树,树上的每条边都有一个权值。现在从根节点开始遍历m条边,求最多能获得多少权值。


分析:很裸的树形dp。f[i,j]表示从节点i开始向下走j条边最多能获得多少权值。

f[i,j]=max(f[lson,j-1]+w[i,lson],f[rson,j-1]+w[i,rson],f[lson,k]+f[rson,j-k-2]+w[i,lson]+w[i,rson])


代码:

var
  n,m,p,x,y,z,i:longint;
  v:array[1..100] of boolean;
  l,r,d:array[1..100] of longint;
  f,a,b:array[1..100,0..100] of longint;

function max(x,y:longint):longint;
begin
  if x>y then exit(x)
         else exit(y);
end;

procedure dp(x:longint);
var
  i,j:longint;
begin
  if l[x]=0 then exit;
  dp(l[x]);
  dp(r[x]);
  for i:=1 to m do
  begin
    f[x,i]:=max(f[l[x],i-1]+d[l[x]],f[r[x],i-1]+d[r[x]]);
    for j:=0 to i-2 do
      f[x,i]:=max(f[x,i],f[l[x],j]+f[r[x],i-j-2]+d[l[x]]+d[r[x]]);
  end;
end;

procedure build(x:longint);
var
  i:longint;
begin
  v[x]:=false;
  for i:=1 to a[x,0] do
    if v[a[x,i]] then
    begin
      if l[x]=0
        then l[x]:=a[x,i]
        else r[x]:=a[x,i];
      d[a[x,i]]:=b[x,i];
      build(a[x,i]);
    end;
end;

begin
  readln(n,m,p);
  fillchar(v,sizeof(v),true);
  for i:=1 to n-1 do
  begin
    readln(x,y,z);
    inc(a[x,0]);
    a[x,a[x,0]]:=y;
    b[x,a[x,0]]:=z;
    inc(a[y,0]);
    a[y,a[y,0]]:=x;
    b[y,a[y,0]]:=z;
    v[y]:=false;
  end;
  fillchar(v,sizeof(v),true);
  build(1);
  dp(1);
  if f[1,m]>=p
    then writeln('TRUE')
    else writeln('FALSE');
  writeln(f[1,m]-p);
end.


你可能感兴趣的:(SSL 1565 将功补过 树形dp)