连接http://www.tyvj.cn/Problem_Show.aspx?id=2064
这题其实是一道贪心,但是如果加入每个点的价值不一样,就是一道树形DP了
这个其实是一棵树套一个背包
F[I,J]表示第i个点的子树及i 用了J个能量 最多获得的个数
F[I,J]:=MAX(F[I,J],F[S[I],K]+F[I,J-K])S[I]是i的孩子
这样一来,复杂度便是1000*100*100是不会超时的。
注意for循环要倒过来。
我在写着题时犯了一个非常sb的错误,就是,没考虑到不消耗就是0的情况
背包循环最小到1 而不是0,改掉以后就对了
这题最优解法是贪心。。。不过拿来练tree dp也是很不错的。
code
var
n,x,y,z,ans,i,sum:longint;
f:array[0..1000,0..110] of longint;
g:array[0..100100] of longint;
next,a,b,c,e:array[0..1005] of longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure dp(k,t:longint);
var
p,y,i,j:longint;
begin
if (c[k]<=t) and (k>0) then
begin
f[k,c[k]]:=1;
if ans<1 then ans:=1;
end;
if (k=0) and (c[k]<=t) then
begin
g[k]:=1;
if ans<1 then ans:=1;
end;
p:=b[k];
while p<>0 do
begin
y:=a[p];
dp(y,min(t,e[y]));
if k<>0 then
for i:=t downto 0 do
for j:=0 to min(t,e[y]) do
if (i-j)>=0 then
if (f[k,i-j]>0) or ((i-j)=0) then
begin
f[k,i]:=max(f[k,i],f[k,i-j]+f[y,j]);
if f[k,i]>ans then ans:=f[k,i];
end;
if k=0 then
for i:=t downto 0 do
for j:=0 to min(t,e[y]) do
if (i-j)>=0 then
if (g[i-j]>0) or ((i-j)=0) then
begin
g[i]:=max(g[i],g[i-j]+f[y,j]);
if g[i]>ans then ans:=g[i];
end;
p:=next[p];
end;
end;
begin
read(n);fillchar(f,sizeof(f),0);
fillchar(g,sizeof(g),0);
fillchar(b,sizeof(b),0);sum:=0;
c[0]:=maxlongint;
for i:=1 to n do
begin
read(x,y,z);
next[i]:=b[x];
b[x]:=i;
a[i]:=i;
e[i]:=z;
c[i]:=y;
if x=0 then sum:=sum+z;
end;
dp(0,sum);
writeln(ans);
end.
写的很丑,见谅!~
本文探讨了一种将树形动态规划(Tree DP)与背包问题相结合的算法思路,通过解决一个具体问题来阐述如何利用这种结合的方式进行高效求解。文章提供了详细的代码实现,并指出了实现过程中容易忽视的细节。
2005

被折叠的 条评论
为什么被折叠?



