有 n n n 个人,根据职位关系形成一棵树,每个人都有一定的快乐指数,并且舞会种不能出现这个人的直接上司(父节点),问邀请哪些人可以使总的快乐数最大?
思路:树形 DP ,令 f [ x ] [ 0 ] f[x][0] f[x][0] 表示以 x x x 为根的子树,且 x x x 不参加舞会的最大快乐值, f [ x ] [ 1 ] f[x][1] f[x][1] 表示参加的最大快乐值,则:
f [ x ] [ 0 ] = ∑ y ∈ s o n ( x ) max ( f [ y ] [ 0 ] , f [ y ] [ 1 ] ) f[x][0]=\sum_{y\in son(x)}\max(f[y][0],f[y][1]) f[x][0]=y∈son(x)∑max(f[y][0],f[y][1])
f [ x ] [ 1 ] = h [ x ] + ∑ y ∈ s o n ( x ) f [ y ] [ 0 ] f[x][1]=h[x]+\sum_{y\in son(x)}f[y][0] f[x][1]=h[x]+y∈son(x)∑f[y][0]
其中 h h h 表示每个人的快乐值
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define MAXN 6010
using namespace std;
vector<int> son[MAXN];
int n,h[MAXN],root,f[MAXN][2],x,y;
bool nr[MAXN];
void dp(int x){
f[x][0]=0;
f[x][1]=h[x];
for(int i=0;i<son[x].size();i++){
int y=son[x][i];dp(y);
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
}
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&h[i]);
for(int i=1;i<n;i++){
scanf("%d%d",&x,&y);
son[y].push_back(x);
nr[x]=true;
}
for(int i=1;i<=n;i++)
if(!nr[i]){
root=i;
break;
}
dp(root);
printf("%d\n",max(f[root][0],f[root][1]));
return 0;
}