LOJ 10160

题面

传送门

Ural 州立大学的校长正在筹备学校的 8080 周年纪念聚会。由于学校的职员有不同的职务级别,可以构成一棵以校长为根的人事关系树。每个资源都有一个唯一的整数编号,从 $1$ 到 $N$ 编号,且对应一个参加聚会所获得的欢乐度。为使每个职员都感到快乐,校长设法使每个职员和其直接上司不会同时参加聚会。

你的任务是设计一份参加聚会者的名单,使总欢乐度最高。

第一行是一个整数 $N$ 

接下来 $N$ 行对应 $N$ 个职员的欢乐度,第 ii 行的一个整数为第 $i$ 个职员的欢乐度 $p_i$

接着是学校的人事关系树,每一行格式为 L K ,表示第 $K$ 个职员是第 $L$ 个职员的直接上司,输入以 0 0 结束。

输出参加聚会者获得的最大欢乐度。

解题思路

树形 DP ,设 $f[i][0]$ 表示第 i 个人不参加时他下面的所有人的最大欢乐值, $f[i][1]$ 表示第 i 个人参加时他下面的所有人的最大欢乐值(包括他)。

然后我们找出树根,进行 dfs, $f[i][0]=sum_{j}^{jin i.son} max(f[j][0],f[j][1]),f[i][1]=sum_{j}^{jin i.son} f[j][0]$ 。

代码

#include<bits/stdc++.h>
using namespace std;
int n;
struct node{//存储树的结点
	int x,isroot;
	vector<int> son;
};
node s[1000001];
int f[1000001][2];
void dfs(int x){
	f[x][0]=0;
	f[x][1]=s[x].x;//如果要选这个人,那么他的快乐值要加上
	for (int i=0;i<s[x].son.size();i++){
		dfs(s[x].son[i]);
		f[x][0]+=max(f[s[x].son[i]][0],f[s[x].son[i]][1]);//状态转移
		f[x][1]+=f[s[x].son[i]][0];
	}
}
int main(){
	cin>>n;
	for (int i=1;i<=n;i++){
		cin>>s[i].x;
		s[i].isroot=1;
	}
	for (int i=1;i<=n-1;i++){
		int x,y;
		cin>>x>>y;
		s[y].son.push_back(x);
		s[x].isroot=0;//如果一个节点有父亲,那么它就不是根节点
	}
	for (int i=1;i<=n;i++){
		if (s[i].isroot){
			dfs(i);
			cout<<max(f[i][0],f[i][1]);
			return 0;
		}
	}
}
原文地址:https://www.cnblogs.com/abc2237512422/p/10344555.html