SSL 1605 二叉苹果树 树形dp

题意:有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。 
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树 
2 5 
\ / 
3 4 
\ / 

现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。 

给定需要保留的树枝数量,求出最多能留住多少苹果。 


分析:先建一棵树,保留每个节点的左右子节点。然后用递归进行树形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]){0<=k<=j-2}。


代码:

var
  n,m,x,y,z,i:longint;
  ld,rd,l,r:array[1..100] of longint;
  v:array[1..100] of boolean;
  a,b:array[1..100,0..100] of longint;
  f: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 dfs(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 begin
               l[x]:=a[x,i];
               ld[x]:=b[x,i];
             end
        else begin
               r[x]:=a[x,i];
               rd[x]:=b[x,i];
             end;
      dfs(a[x,i]);
    end;
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]+ld[x],f[r[x],i-1]+rd[x]);
    for j:=0 to i-2 do
      f[x,i]:=max(f[x,i],f[l[x],j]+f[r[x],i-2-j]+ld[x]+rd[x]);
  end;
end;

begin
  readln(n,m);
  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;
  end;
  fillchar(v,sizeof(v),true);
  dfs(1);
  dp(1);
  writeln(f[1,m]);
end.


你可能感兴趣的:(SSL 1605 二叉苹果树 树形dp)