[vijos P1180] 选课

这一周竟然都没好好码题目,不过至少把这题的树形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!

原文地址:https://www.cnblogs.com/Sky-Grey/p/3601305.html