ac代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 6e3 + 5;
int r[N];
bool worker[N]; //标记第i个人是否有上司,用于找出校长
int n;
vector<int> edge[N]; //由于不一定是二叉树,故用图的方式存树
int dp[N][2]; //树上dp的特殊定义方式
//dp[i][1]代表第i个人参加时,i作为根节点的子树最优解;dp[i][0]代表第i个人不参加时,i作为根节点的子树最优解
//树这种结构更适合用dfs进行遍历
void dfs(int o)
{
dp[o][1] = r[o];
int len = edge[o].size();
for (int i = 0; i < len; i++)
{
dfs(edge[o][i]);
dp[o][1] += dp[edge[o][i]][0];
dp[o][0] += max(dp[edge[o][i]][1], dp[edge[o][i]][0]);
}
}
int main()
{
int l, k;
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> r[i];
for (int i = 0; i < n - 1; i++)
{
cin >> l >> k;
worker[l] = 1;
edge[k].push_back(l);
}
//找校长(树的根节点)
int headmaster;
for (int i = 1; i <= n; i++)
{
if (!worker[i])
{
headmaster = i;
break;
}
}
//从根节点开始遍历
dfs(headmaster);
cout << max(dp[headmaster][1], dp[headmaster][0]);
return 0;
}
树上dp的两个关键点
- dp数组的定义方式,定义dp[N][2],其意义为以i为根节点的子树的最优解。
- 递推的方式,对于树或者图这种数据结构,要使用dfs进行遍历,而不能用bfs,因为动态规划考虑递推,当递推到后面的式子是由前面推得的,故先要推导出叶子节点的有效值。