题意:玩过Diablo的人对技能树一定是很熟悉的。一颗技能树的每个结点都是一项技能,要学会这项技能则需要耗费一定的技能点数。只有学会了某一项技能以后,才能继续学习它的后继技能。每项技能又有着不同的级别,级别越高效果越好,而技能的升级也是需要 耗费技能点数的。
有个玩家积攒了一定的技能点数,他想尽可能地利用这些技能点数来达到最好的效果。因此他给所有的级别都打上了分,他认为效果越好的分数也越高。现在他要你帮忙寻找一个分配技能点数的方案,使得分数总和最高。
分析:先建树,然后转换成二叉树。这样问题就变成了选课的升级版。方程就不多说了。
唉一开始无限WA并且怎么都找不到那里错了。最后灵光一闪,机智的我发现了升级需要的技能点可能为0,所以就在树形dp内把循环的起点改成了0,然后就AC了……超级无语……
代码:
var n,m,a1,root,s,x,i,j:longint; num:array[0..20,1..20] of longint; nam,fnam:array[1..20] of string; f:array[-1..400,0..100] of longint; d,w,l,r:array[0..400] of longint; a:array[0..400,0..400] of longint; procedure build(x:longint); var i:longint; begin for i:=1 to a[x,0]-1 do r[a[x,i]]:=a[x,i+1]; if a[x,0]>0 then l[x]:=a[x,1]; for i:=1 to a[x,0] do build(a[x,i]); end; function max(x,y:longint):longint; begin if x>y then exit(x) else exit(y); end; procedure dp(x:longint); var i:longint; begin if x=-1 then exit; dp(l[x]); dp(r[x]); for i:=0 to m do begin f[x,i]:=f[r[x],i]; for j:=0 to i-d[x] do f[x,i]:=max(f[x,i],f[l[x],j]+f[r[x],i-j-d[x]]+w[x]); end; end; begin readln(n); a1:=0; root:=0; for i:=1 to n do begin readln(nam[i]); readln(fnam[i]); readln(s); for j:=1 to s do begin inc(a1); num[i,j]:=a1; read(x); d[a1]:=x; if j>1 then begin inc(a[num[i,j-1],0]); a[num[i,j-1],a[num[i,j-1],0]]:=num[i,j]; end; end; readln; for j:=1 to s do begin read(x); w[num[i,j]]:=x; end; readln; end; for i:=1 to n do begin x:=root; for j:=1 to n do if nam[j]=fnam[i] then begin x:=j; break; end; inc(a[num[x,1],0]); a[num[x,1],a[num[x,1],0]]:=num[i,1]; end; readln(m); for i:=1 to n do begin read(x); for j:=1 to x do begin d[num[i,j]]:=0; w[num[i,j]]:=0; end; end; for i:=0 to a1 do begin l[i]:=-1; r[i]:=-1; end; build(root); dp(root); writeln(f[root,m]); end.