题目描述
Ural周立大学的校长正在筹备学校的80周年纪念聚会。由于学校的职员有不同的职务级别,可以构成一棵以校长为根的人事关系树。每个职员都有一个唯一的整数编号(范围在1到N之间),并且对应一个参加聚会所获得的欢乐度。为了使每个参加聚会者都感到欢乐,校长想设法使每个职员和他(她)的直接上司不会同时参加聚会。
你的任务是设计一份参加聚会者的名单,使总的欢乐度最高。
输入格式
输入的第一行是一个整数N,1<= N <= 6000
以下的N行是对应的N个职员的欢乐度(欢乐度是一个从-128到127之间的整数)
接着是学校的人事关系树,树的每一行格式如下:
< L > < K >
表示第K个职员是第L个职员的直接上司。
输入以0 0表示结束
输出格式
输出:参加聚会者获得的最大总欢乐度
样例数据
样例输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
样例输出
5
题目分析
树型动规,与战略游戏类似
设f[i][0]表示不邀请i的最高欢乐度,f[i][1]表示邀请i的最高欢乐度
若邀请i,则不能邀请i的儿子,若不邀请i,则可邀请i的儿子也可不邀请i的儿子
取个最大值即可
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const long long Get_Int() {
long long num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
struct Edge {
int to,next;
} Edge[50005];
int n,cnt=0,Head[50005],f[50005][5],vst[50005],Joy[50005],root;
void AddEdge(int x,int y) {
cnt++;
Edge[cnt].to=y;
Edge[cnt].next=Head[x];
Head[x]=cnt;
}
void TreeDp(int root) {
f[root][0]=0;
f[root][1]=Joy[root];
for(int i=Head[root]; i; i=Edge[i].next) {
int Next=Edge[i].to;
TreeDp(Next);
f[root][0]=max(f[root][0],max(f[root][0]+f[Next][1],f[root][0]+f[Next][0]));
f[root][1]=max(f[root][1],f[Next][0]+f[root][1]);
}
}
int main() {
n=Get_Int();
for(int i=1; i<=n; i++)Joy[i]=Get_Int();
while(true) {
int x=Get_Int(),y=Get_Int();
if(x==0&&y==0)break;
AddEdge(y,x);
vst[x]=1;
}
for(int i=1; i<=n; i++)if(!vst[i])root=i;
TreeDp(root);
cout<<max(f[root][0],f[root][1])<<endl;
return 0;
}