蓝桥杯 ALGO-4 算法训练 结点选择

问题描述

有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?

输入格式

第一行包含一个整数 n 。 接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。 接下来一共 n-1 行,每行描述树上的一条边。

输出格式

输出一个整数,代表选出的点的权值和的最大值。

样例输入

5 1 2 3 4 5 1 2 1 3 2 4 2 5

样例输出

12

样例说明

选择3、4、5号点,权值和为 3+4+5 = 12 。

数据规模与约定

对于20%的数据, n <= 20。 对于50%的数据, n <= 1000。 对于100%的数据, n <= 100000。 权值均为不超过1000的正整数。

题目给出的数据不一定是二叉树,用图来处理。 每个点的最大权值有取当前这个点和不取当前这个点两种情况。取当前点,则不能取与它相邻的任何点;不取当前点,则取与它相邻点的最大值,然后对所有相邻点求和就是当前点所能得到的最大值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdio>
#include <vector>

using namespace std;

vector<vector<int> > v;
int dp[100000][2];

void dfs(int root, int pre) {
for (int i = 0; i < v[root].size(); i++) {
if (v[root][i] != pre) {
dfs(v[root][i], root);
dp[root][0] += max(dp[v[root][i]][0], dp[v[root][i]][1]);
dp[root][1] += dp[v[root][i]][0];
}
}
}

int main() {
int n = 0, a = 0, b = 0;
scanf("%d", &n);
v.resize(n);
for (int i = 0; i < n; i++) {
scanf("%d", &dp[i][1]);
}
for (int i = 0; i < n - 1; i++) {
scanf("%d %d", &a, &b);
v[a - 1].push_back(b - 1);
v[b - 1].push_back(a - 1);
}
dfs(0, -1);
printf("%d", max(dp[0][0], dp[0][1]));
return 0;
}