luoguP1352 没有上司的舞会
给定一棵有N个节点的树,节点i的权值为r[i],需要选出一些不相邻的节点,使得权值之和最大,求最大值。
1<=N<=6E3; -128<=r[i]<=127
分析:自下而上dp,对于每个节点,可以选或者不选。如果选,那么其子节点不能选;如果不选,那么其子节点可以选或不选。
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<int> r(n);
for (int i = 0; i < n; i++) {
std::cin >> r[i];
}
std::vector<int> fa(n, -1);
std::vector<std::vector<int>> adj(n);
for (int i = 1; i < n; i++) {
int x, y;
std::cin >> x >> y;
x--, y--;
fa[x] = y;
adj[y].push_back(x);
}
int root = -1;
for (int i = 0; i < n; i++) {
if (fa[i] == -1) {
root = i;
break;
}
}
std::vector<std::array<int,2>> dp(n);
auto dfs = [&](auto self, int x) -> void {
dp[x][0] = 0;
dp[x][1] = r[x];
for (auto i : adj[x]) {
self(self, i);
dp[x][0] += std::max(dp[i][0], dp[i][1]);
dp[x][1] += dp[i][0];
}
};
dfs(dfs, root);
std::cout << std::max(dp[root][0], dp[root][1]) << "\n";
}
int main() {
std::cin.tie(0)->sync_with_stdio(0);
int t = 1;
while (t--) solve();
return 0;
}