LOJ 10160 - 「一本通 5.2 练习 3」周年纪念晚会 / 没有上司的晚会
题面
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}^{j\in i.son} max(f[j][0],f[j][1]),f[i][1]=\sum_{j}^{j\in 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; } } }