题目已经说了这是一棵树,而这道题显然不是重心或者lca之类的东西,所以我们考虑树形DP。(一句废话)
首先考虑如果节点i不去舞会时以i为根的子树的快乐指数最大值,显然就是每个以i的儿子为根的子树的最大值之和。
如果节点i参加舞会,那么相应的最大值就是i的每个儿子都不去时,以i的儿子为根的最大值之和,再加上i的快乐指数。
所以状态和转移方程就很显然了,设 f[i][0/1] f [ i ] [ 0 / 1 ] 表示节点i参加/不参加舞会时,以i为根的子树的最大值,则 f[i][0]=∑max(f[j][0],f[j][1]) f [ i ] [ 0 ] = ∑ max ( f [ j ] [ 0 ] , f [ j ] [ 1 ] ) , f[i][1]=(∑f[j][0])+Ri f [ i ] [ 1 ] = ( ∑ f [ j ] [ 0 ] ) + R i ,其中 j 为 i 的儿子。
附上本蒟蒻丑陋的代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=6000;
int n,a[N+10],f[N+10][2],rt,cnt[N+10],to[N+10],pre[N+10],h[N+10];
void dfs(int x)
{
for(int i=h[x];i;i=pre[i])
{
int v=to[i];
dfs(v);//先dp子节点
f[x][1]+=f[v][0];//如果当前节点去舞会
f[x][0]+=max(f[v][0],f[v][1]);//如果当前节点不去舞会
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&f[i][1]);
for(int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&y,&x);
to[i]=y;pre[i]=h[x];h[x]=i;cnt[y]++;//邻接表存边
if(cnt[x]==0)rt=x;//寻找根节点
}
dfs(rt);printf("%d\n",max(f[rt][0],f[rt][1]));return 0;
}