例题:https://www.luogu.com.cn/problem/P1352
概要:某大学有 n 个职员,编号为 1 - N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 ,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数
我们可以定义 F[i][0/1] 代表以 i 为根的子树的最优解(第二维的值为 0 代表 不参加舞会的情况,1 代表 参加舞会的情况)。
- 显然,我们可以推出下面两个状态转移方程(其中下面的 x 都是 i 的儿子):
(上司不参加舞会时,下属可以参加,也可以不参加)
(上司参加舞会时,下属都不会参加)
我们可以通过 DFS,在返回上一层时更新当前结点的最优解。
代码
#include <algorithm>#include <cstdio>using namespace std;struct edge {int v, next;} e[6005];int head[6005], n, cnt, f[6005][2], ans, is_h[6005], vis[6005];void addedge(int u, int v) { //建图e[++cnt].v = v;e[cnt].next = head[u];head[u] = cnt;}void calc(int k) {vis[k] = 1;for (int i = head[k]; i; i = e[i].next) { // 枚举该结点的每个子结点if (vis[e[i].v]) continue;calc(e[i].v);f[k][1] += f[e[i].v][0];f[k][0] += max(f[e[i].v][0], f[e[i].v][1]); //转移方程}return;}int main() {scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%d", &f[i][1]);for (int i = 1; i < n; i++) {int l, k;scanf("%d%d", &l, &k);is_h[l] = 1;addedge(k, l);}for (int i = 1; i <= n; i++)if (!is_h[i]) { // 从根结点开始DFScalc(i);printf("%d", max(f[i][1], f[i][0]));return 0;}}
