题目大意
对于一个二叉树,除根节点外,每个节点都有相应的一个权值。在此基础上,求保留多少个点使得其仍然满足树的性质且权值总和最大。
分析
先建树。
ch[v,1],ch[v,2]分别存V节点的左右孩子。dp[v,l]存以V为根的树保留L个节点的最大权和。Num[v]为点v的权值。
dp[v,l]=max{dp[ch[v,1],j]+dp[ch[v,2],l-j-1]+num[v]} (0<=j<=l-1)
这里特别指出,为了使其仍然为二叉树,我们一定要保留根节点,因此j<=l-1。
然后,可以减枝。
然后2,注意边界:
如果l=0,那么dp[v,l]=0。
如果点v没有孩子,那么dp[v,l]=v的权值。
然后3,因为输入的是要保留m条边,而转化后的题目是保留nm个点,所以输入的m要加1.
代码
var
f:array[0..200,0..200] of longint;
a:array[0..200,1..3] of longint;
b:array[0..200,0..200] of longint;
v,num:array[0..200] of longint;
i,j,k,l:longint;
n,m:longint;
ans:longint;
procedure make(v:longint);
var
i,j,k:longint;
begin
for i:=1 to n do
begin
if b[v,i]>0 then
begin
a[v,1]:=i;
num[i]:=b[v,i]-1;
b[v,i]:=-1; b[i,v]:=-1;
make(i);
break;
end;
end;
for i:=1 to n do
begin
if b[v,i]>0 then
begin
a[v,2]:=i;
num[i]:=b[v,i]-1;
b[v,i]:=-1; b[i,v]:=-1;
make(i);
break;
end;
end;
end;
procedure dfs(r,l:longint);
var
i,j,k:longint;
begin
if f[r,l]<>0 then exit;
if l=0
then
begin
f[r,l]:=0;
exit;
end;
if (a[r,1]=0) and (a[r,2]=0)
then begin
f[r,l]:=num[r];
exit;
end;
for i:=0 to l-1 do
begin
dfs(a[r,1],i);
dfs(a[r,2],l-i-1);
if f[r,l]<f[a[r,1],i]+f[a[r,2],l-i-1]+num[r]
then
f[r,l]:=f[a[r,1],i]+f[a[r,2],l-i-1]+num[r];
end;
end;
begin
readln(n,m);
m:=m+1;
for i:=1 to n-1 do
begin
readln(j,k,l);
b[j,k]:=l+1;
b[k,j]:=l+1;
end;
fillchar(f,sizeof(f),0);
fillchar(v,sizeof(v),0);
fillchar(a,sizeof(a),0);
v[0]:=1;
make(1);
dfs(1,m);
writeln(f[1,m]);
end.