问题描述
有一棵 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; }
|