题目大意;
Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数Ri。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。
1<=N<=6000
-128<=Ri<=127
题解:
一道树形dp的模板题,
因为只存在一棵树,所以只需要找到根节点然后树形dp即可
f[i][0]表示以i为根的子树没有选上司i的最大快乐指数
f[i][1]表示以i为根的子树选了上次i的最大快乐指数
因为选了i的儿子就不能选i
那么就有了很显然的转移:
f[i][0]=max{f[i][0],max{f[i][0]+f[son][0],f[i][0]+f[son][1]} }
f[i][1]=max{f[i][1],f[i][1]+f[son][0]}
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 6005
int f[N][2],a[N],next[N],list[N],op[N],x[N],n,m,y;
int max(int aa,int bb)
{
if (aa>bb) return aa;
return bb;
}
void add(int rp,int aa)
{
next[rp]=list[aa];
list[aa]=rp;
}
void dfs(int dep)
{
f[dep][0]=0;
f[dep][1]=a[dep];
int rp=list[dep];
while (rp)
{
int i=x[rp];
dfs(i);
f[dep][0]=max( f[dep][0] , max(f[dep][0]+f[i][0] , f[dep][0]+f[i][1]) );
f[dep][1]=max( f[dep][1] , f[dep][1]+f[i][0] );
rp=next[rp];
}
}
int main()
{
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
for (int i=1; i<n; i++)
{
scanf("%d%d",&x[i],&y);
if (x[i]==0&&y==0) break;
add(i,y);
op[x[i]]=1;
}
int root;
for (int i=1; i<=n; i++)
if (!op[i]) root=i;
dfs(root);
printf("%d",max(f[root][0],f[root][1]));
return 0;
}