题目描述
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入
第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0 0
输出
输出最大的快乐指数。
Sample input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
Sample output
5
题解
一道比较经典的树形DP问题,出自HDU 1520。
由题目我们可以得知,i是否参加舞会,之与i的下属参不参加舞会有关。
在这里我们用:
f[i,0] 表示在i不参加舞会的情况下,以i为根的子树能达到的最大快乐指数和。
f[i,1] 表示在i参加舞会的情况下,以i为根的子树能达到的最大快乐指数和。
这样就比较容易得出:
f[i,0]:=∑max(f[j,0],f[j,1])
f[i,1]:=r[i]+∑f[j,0]
其中j为i的直系下属
附上Pascal代码:
program p1352;
type node=record
son:longint; //son 记录下属
next:longint; //next 记录同上司的直系下属所处edge数组的编号 i
end;
var i,j,k,g,l,root,n:longint;
r,head:array[0..6001] of longint;
f:array[0..6001,0..1] of longint;
edge:array[0..6001] of node;
function max(a,b:longint):longint;
begin
if a>b then exit(a)
else exit(b);
end;
procedure dfs(x:longint);
var y,i:longint;
begin
if head[x]=-1 then
begin
f[x,0]:=0;f[x,1]:=r[x];
end
else
begin
i:=head[x];
f[x,1]:=r[x];
while i<>-1 do
begin
y:=edge[i].son;
dfs(y);
f[x,0]:=f[x,0]+max(f[y,0],f[y,1]);
f[x,1]:=f[x,1]+f[y,0];
i:=edge[i].next; //dfs the same father's another son;继续寻找相同上司的直系下属
end;
end;
end;
begin
read(n);
fillchar(f,sizeof(f),0);
for i:=1 to 6001 do
head[i]:=-1;
for i:=1 to n do
read(r[i]);
for i:=1 to n-1 do
begin
read(l,k);
edge[i].son:=l;
edge[i].next:=head[k];
head[k]:=i;
end;
root:=n*(n+1) div 2;
for i:=1 to n-1 do
root:=root-edge[i].son; //find out the root;找出当前最大的BOOS
dfs(root);
writeln(max(f[root,0],f[root,1])) ;
end.