【解题报告】公司聚会

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/TengWan_Alunl/article/details/74987554

题目来源:vijos1418.
参考自:raoyu的题解(在第一面,往下拉一点)
其实这是一个在树上的01背包问题。这道题与经典的公司聚会不同,因为上司的定义由父结点改为了所有祖先。这样问题也由树形dp变为了01背包。由于题目中有一个非常重要的条件,“员工的编号会大于他的直接上司的编号”,我们可以直接循环而不用建立树结构。
设f[v,m]是以v为根的子树花费m元最大可以获得的兴奋指数。则在循环到v以前,f[v,m]表示以v为根的子树(不包括v)花费m元最大可以获得的兴奋指数;在循环到v时及以后,f[v,m]表示以v为根的子树(可能包括v,取决于取v的儿子们值大还是v的值大)花费m元最大可以获得的兴奋指数。

这次具体的解释写在注释里。

PS:这题数据范围很坑人,m最大109。我还以为是10^9打成了109。

AC代码

program vijos1418;
var i,j,k,n:longint;
    m:longint;
    c,e,fa:array[0..1024]of longint;
    f:array[0..1024,0..109]of longint;
function max(a,b:longint):longint;
begin
  if(a>b)then exit(a);
  exit(b);
end;
begin
    readln(n,m);
    for i:=2 to n do read(fa[i]);
    for i:=1 to n do read(c[i]);
    for i:=1 to n do read(e[i]);

    for i:=n downto 1 do begin//倒序进行,确保在更新每一个结点时,该节点的所有子节点都已经被更新过。
      for j:=c[i] to m do f[i,j]:=max(f[i,j],e[i]);//此时f[i,j]仍然表示以i为根的子树(不包括i)花费j元最大可以获得的兴奋指数,将其与自身兴奋指数比较,留下大者。

      for j:=m downto 0 do
        for k:=0 to j do
            f[ fa[i],j ]:=max(f[fa[i],j], f[fa[i],j-k]+f[i,k]);//这三行背包
    end;

    writeln(f[1,m]);
end.

另:
某神犇的AC结果:
某神犇的AC结果
我的AC结果:
我的AC结果
这差距怎么这么大0.0,莫非有什么更厉害的算法。以后再来研究。

猜你喜欢

转载自blog.csdn.net/TengWan_Alunl/article/details/74987554
今日推荐