这一周竟然都没好好码题目,不过至少把这题的树形DP给摸了个大概。吐槽一下自己,递归已经基本不会用了…QAQ!按老师的话来说“太危险了!”
此题用到多叉树转二叉树,左孩子是真正意义的孩子(先修完自己才能修左孩子),右孩子是同辈。着实是一个好方法,同时我也不知道多叉树该怎么写,多套个循环扫?Anyway转二叉搞会了。
f[x,y]表示,以x为根节点的子树,上y节课可以修到的最大学分。(没看解题前我的思路是,f[x,y]表示从1~x中选y节课可以得到的最大学分QAQ错错错)
最后犯的小错误是在DP子函数里面,for k:=0 to num-1,一开始把0写成1了,所以导致所有的答案都偏小一些。写成1的话,就没把c[root]+f[r[root],num-1]的情况给算进去。
DP就是精简,但是递推方程就是难想,想象力得多丰富才想得到,出题者又得多厉害出得出这种题。
program vijos_p1180; var f:Array[0..301,0..301] of longint; l,r,c,p:array[0..301] of integer; n,m,i,d,t,tt,root,ans:integer; flag:boolean; function max(a,b:integer):integer; begin if a>b then exit(a) else exit(b); end; function dp(root,num:integer):integer; var k,t:integer; begin t:=0; if (root=0) or (num=0) then exit(0); if f[root,num]>0 then exit(f[root,num]); f[root,num]:=dp(r[root],num); if (num=1) and (c[root]>f[root,num]) then f[root,num]:=c[root]; for k:=0 to num-1 do begin t:=dp(l[root],k)+dp(r[root],num-k-1)+c[root]; if t>f[root,num] then f[root,num]:=t; end; dp:=f[root,num]; end; begin readln(n,m); flag:=false; for i:=1 to n do begin readln(d,c[i]); p[i]:=d; if (d=0) and (flag=false) then begin flag:=true; root:=i; end; if l[d]=0 then l[d]:=i else begin t:=l[d]; while r[t]<>0 do t:=r[t]; r[t]:=i; end; end; ans:=dp(root,m); writeln(ans); end.
测试数据 #0: Accepted, time = 0 ms, mem = 1096 KiB, score = 20
测试数据 #1: Accepted, time = 15 ms, mem = 1092 KiB, score = 20
测试数据 #2: Accepted, time = 15 ms, mem = 1092 KiB, score = 20
测试数据 #3: Accepted, time = 46 ms, mem = 1092 KiB, score = 20
测试数据 #4: Accepted, time = 62 ms, mem = 1096 KiB, score = 20
P.S. 为什么别人都是0ms难道我写的有什么问题么,看了别人代码感觉我多叉转二叉写麻烦了,不过我完全按照自己想象力去写的。
P.S.2 此题也是tyvj 1051 选课。tyvj感觉好久没人维护了呀…毕竟是自己最开始用的oj感情还是深的T^T!