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;
}
}
}

浙公网安备 33010602011771号