技能树(SGOI)
skill.pas/c/cpp
【问题描述】
玩过 Diablo 的人对技能树一定是很熟悉的。一颗技能树的每个结点都是一项技能,要学会这项技能则需
要耗费一定的技能点数。只有在学会了某一项技能以后,才能继续学习它的后继技能。每项技能又有着不同的级
别,级别越高效果越好,而技能的升级也是需要耗费技能点数的。
有个玩家积攒了一定的技能点数,他想尽可能地利用这些技能点数来达到最好的效果,因此他给所有技能的
所有级别都打上了分,他认为效果越好的则分数越高。现在他要你帮忙寻找一个分配技能点数的方案,使得分数
总和最高。
【输入格式】
第一行是一个整数 n(1<=n<=20),表示所有不同技能的总数。接下来依次给出了这 n 个不同技能的详细
描述。每个技能描述共包括 5 行,第一行是该技能的名称,第二行是该技能在技能树中的父技能的名称,为空
则表示该技能不需要任何的先修技能便能学习。第三行是一个整数 L(1<=L<=20) ,表示这项技能所拥有的最
高等级。第四行共有 L 个整数,其中第 i 个整数表示把这项技能从第 i-1 级升到第 i 级所需要的技能点数(0
级表示没有学习过)。第五行也包括了 L 个整数,其中第 i个整数表示该玩家对这项技能的第 i 级的效果评分,
分数不超过 20。在技能描述之后是玩家所用角色的描述,共有两行。第一行是一个整数 P(0<=P<=100),表
示目前所拥有的技能点数。接下来一行是 n 个整数,依次表示角色当前所习得的技能级别,0 表示尚未学习。这里
不会出现非法的情况,譬如在没有学习某项技能的时候已经习得了它的后继技能。
【输出格式】
只需包括一个整数 S,表示你的技能点最佳分配方案所得到的分数总和。
【输入样例】
3
Freezing Arrow
Ice Arrow
3
3 3 3
15 4 6
Ice Arrow
Cold Arrow
2
4 3
10 17
Cold Arrow
3
3 3 2
15 5 2
10
0 0 1
【输出样例】
42
【时间限制】
1s
【空间限制】
64M
//------------------------------------------------------------------------------------------------
分析:树形动规,多叉树转二叉树.
f[i,j]表示以i为根的子树,花j点技能点,能得到的最大分数.
枚举给左右儿子分配的点数进行转移,记忆化搜索.
code:
type skill=record n,f:string; l:longint; v,p:array[0..21] of longint; end; const maxn=21; maxp=101; var s:array[0..maxn] of skill; f:array[0..maxn,0..maxp] of longint; learn,l,r:array[0..maxn] of longint; n,i,j,fa,tmp,p,ans:longint; function find(st:string):longint; var o:longint; begin for o:=1 to n do if s[o].n=st then exit(o); exit(0); end; function maxx(a,b:longint):longint; begin if a>b then exit(a); exit(b); end; function DP(t,m:longint):longint; var max,now,o,cost,value,q:longint; begin if f[t,m]>=0 then exit(f[t,m]); max:=DP(r[t],m); //不学这种技能 if learn[t]>0 then //已经学过的话,向下接着学 for o:=1 to m do begin now:=DP(l[t],o)+DP(r[t],m-o); max:=maxx(max,now); end; cost:=0; value:=0; for o:=learn[t]+1 to s[t].l do //把这个技能接着学下去 begin cost:=cost+s[t].v[o]; value:=value+s[t].p[o]; for q:=0 to m-cost do begin now:=DP(l[t],q)+DP(r[t],m-cost-q)+value; max:=maxx(max,now); end; end; f[t,m]:=max; exit(max); end; begin assign(input,'skill.in'); reset(input); assign(output,'skill.out'); rewrite(output); readln(n); for i:=1 to n do begin readln(s[i].n); readln(s[i].f); readln(s[i].l); for j:=1 to s[i].l do read(s[i].v[j]); readln; for j:=1 to s[i].l do read(s[i].p[j]); readln; end; readln(P); for i:=1 to n do read(learn[i]); for i:=1 to n do begin fa:=find(s[i].f); if l[fa]=0 then l[fa]:=i else begin tmp:=l[fa]; while r[tmp]<>0 do tmp:=r[tmp]; r[tmp]:=i; end; end; fillchar(f,sizeof(f),255); for i:=0 to maxp do f[0,i]:=0; ans:=DP(l[0],P); writeln(ans); close(input); close(output); end.