结点选择
问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入
第一行包含一个整数 n 。 接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。 接下来一共 n-1 行,每行描述树上的一条边。
输出
输出一个整数,代表选出的点的权值和的最大值。
输入例子 1
5
1 2 3 4 5
1 2
1 3
2 4
2 5
输出例子 1
12
实现代码
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAX 100000+5
using namespace std;
struct Edge {
int to, next;
}edge[MAX << 1];
int n, i, x, y ,cnt = 0;
int dp[MAX][2];
int head[MAX];
void Link(int x, int y) {
edge[cnt].to = y; //第cnt条边的目标点
edge[cnt].next = head[x]; //换链头,即原本的链头成为新链头的下一个点
head[x] = cnt++; //x点的其实边所在下标
edge[cnt].to = x; //因为是无向边,所以两个都要记录
edge[cnt].next = head[y];
head[y] = cnt++;
}
void dfs(int now, int pre){
for (int i = head[now]; i != -1; i = edge[i].next) {
if (edge[i].to == pre) continue; //避免重复计算
int next = edge[i].to;
dfs(next, now);
dp[now][0] += max(dp[next][0], dp[next][1]); //此点不选,则下个点可以选可以不选
dp[now][1] += dp[next][0]; //此点选择,则下点只有不选一种情况
}
}
int main() {
memset(head, -1, sizeof(head));
memset(dp, 0, sizeof(dp));
cin >> n;
for (i = 1; i <= n; i++) cin >> dp[i][1];
for (i = 1; i < n; i++) {
cin >> x >> y;
Link(x, y);
}
dfs(1, 0);
int ans = max(dp[1][0],dp[1][1]);
cout << ans << endl;
return 0;
}