题目地址:
https://www.luogu.com.cn/problem/P1352
某大学有 n n n个职员,编号为 1 ∼ n 1\sim n 1∼n。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r i r_i ri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式:
输入的第一行是一个整数
n
n
n。
第
2
2
2到第
(
n
+
1
)
(n + 1)
(n+1)行,每行一个整数,第
(
i
+
1
)
(i+1)
(i+1)行的整数表示
i
i
i号职员的快乐指数
r
i
r_i
ri。
第
(
n
+
2
)
(n + 2)
(n+2)到第
2
n
2n
2n行,每行输入一对整数
l
,
k
l, k
l,k,代表
k
k
k是
l
l
l的直接上司。
输出格式:
输出一行一个整数代表最大的快乐指数。
数据范围:
对于
100
%
100\%
100%的数据,保证
1
≤
n
≤
6
×
1
0
3
1\leq n \leq 6 \times 10^3
1≤n≤6×103,
−
128
≤
r
i
≤
127
-128 \leq r_i\leq 127
−128≤ri≤127,
1
≤
l
,
k
≤
n
1 \leq l, k \leq n
1≤l,k≤n,且给出的关系一定是一棵树。
所有点形成一个森林,设 f [ v ] [ 0 ] f[v][0] f[v][0]表示 v v v为根的子树如果 v v v不参加舞会,能得到的最大快乐指数, f [ v ] [ 1 ] f[v][1] f[v][1]表示 v v v为根的子树如果 v v v参加舞会,能得到的最大快乐指数。那么在计算 f [ v ] f[v] f[v]的时候,可以先递归计算其所有孩子的 f f f值,然后考虑 f [ v ] f[v] f[v],对于 f [ v ] [ 0 ] f[v][0] f[v][0],由于 v v v没参加,所以其子树树根可以参加也可以不参加,所以 f [ v ] [ 0 ] = ∑ v → u max { f [ u ] [ 0 ] , f [ u ] [ 1 ] } f[v][0]=\sum_{v\to u} \max\{f[u][0],f[u][1]\} f[v][0]=v→u∑max{f[u][0],f[u][1]}对于 f [ v ] [ 1 ] f[v][1] f[v][1],由于 v v v参加了,所以其所有子树树根都不能参加,所以 f [ v ] [ 1 ] = ∑ v → u f [ u ] [ 0 ] f[v][1]=\sum_{v\to u}f[u][0] f[v][1]=v→u∑f[u][0]最后对于所有树根 v i v_i vi,求一下 ∑ i max { f [ v i ] [ 0 ] , f [ v i ] [ 1 ] } \sum_i \max\{f[v_i][0],f[v_i][1]\} ∑imax{f[vi][0],f[vi][1]}即为答案。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 6010;
int n;
int h[N], e[N], ne[N], idx;
int r[N];
bool is_boss[N];
int f[N][2];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u) {
f[u][1] = r[u];
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
dfs(v);
f[u][1] += f[v][0];
f[u][0] += max(f[v][0], f[v][1]);
}
}
int main() {
memset(h, -1, sizeof h);
fill(is_boss, is_boss + N, true);
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &r[i]);
for (int i = 1; i <= n - 1; i++) {
int a, b;
scanf("%d%d", &a, &b);
add(b, a);
is_boss[a] = false;
}
int res = 0;
for (int i = 1; i <= n; i++)
if (is_boss[i]) {
dfs(i);
res += max(f[i][0], f[i][1]);
}
printf("%d\n", res);
}
时空复杂度 O ( n ) O(n) O(n)。