题解
树形dp求解 d[i][0]表示i没参加以i为根的子树最大快乐值 d[i][1]表示i参加以i为根的子树最大快乐值
如果i不参加则可以从所有子节点j参加或者不参加转移来 即 d[i][0] = a[i] + ∑max(d[i][0], d[i][1])
如果i参加则不能从子节点j参加的情况转移来 即d[i][1] = a[i] + ∑d[j][0]
求d的过程使用dfs遍历 先递归下去回溯时计算 最后输出根去或不去取max
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 6e3 + 10;
int a[MAXN], r[MAXN], d[MAXN][2]; //d[i][0]第i节点不选中i子树最大值 1选中
vector<int> b[MAXN];
void DFS(int x)
{
d[x][0] = 0, d[x][1] = a[x];
for (auto y : b[x])
{
DFS(y); //先递归回溯时计算d
d[x][0] += max(d[y][0], d[y][1]); //如果父节点不选 则加上子节点选或者不选
d[x][1] += d[y][0]; //如果父节点选 则只能加子节点不选
}
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n;
cin >> n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++)
{
int l, k;
scanf("%d%d", &l, &k);
b[k].push_back(l);
r[l] = 1;
}
for (int i = 1; i <= n; i++)
if (!r[i]) //得到根
{
DFS(i);
cout << max(d[i][0], d[i][1]) << endl;
}
return 0;
}