题意: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.