有一个一维的本类题,大盗阿福,本题是从一维扩展而来的题,变成了树上的问法。
使用(f[i])来进行状态表示是不行的,原因是这样没有表示i这个结点是能选择还是不能选择,只有它表示清楚了,它的孩子才知道本身应不应该选择。
(f[i][0]) 不选择i这个结点,总共最大权值和是多少
(f[i][1]) 选择i这个结点,总共最大权值和是多少
比如父节点选择了,那么子节点就不可以选择。父节点不选择,那么子节点是可以选择(也可以不选)。
树的话,需要把树保存下来,就是需要一个邻接表。
并且为了遍历树,可以使用深度优先搜索去遍历。
#include <bits/stdc++.h>
using namespace std;
const int N = 6010;
int h[N], e[N], ne[N], idx;//邻接表专用
int happy[N]; //快乐值
int has_fa[N]; //是不是有父节点
int f[N][2]; //dp的状态结果数组
int n;
//构建邻接表
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
//通过深度优先搜索,对树进行遍历
void dfs(int u) {
//初始值
f[u][1] = happy[u];
for (int i = h[u]; i != -1; i = ne[i]) { //遍历邻接表
int j = e[i];
dfs(j); //继续探索它的孩子,它的值是由它的孩子来决定的
f[u][1] += f[j][0]; //它选择了,它的孩子就不能再选
f[u][0] += max(f[j][0], f[j][1]); //它不选择,那么它的每一个孩子,都是可以选择或者不选择的
}
}
int main() {
//优化输入
ios::sync_with_stdio(false);
cin >> n;
for (int i = 1; i <= n; i++)cin >> happy[i]; //读入每个的快乐值
//邻接表表头初始化
memset(h, -1, sizeof h);
//读入树
for (int i = 0; i < n - 1; i++) {
int x, y;
cin >> x >> y;
add(y, x);
has_fa[x] = 1;
}
//从1开始找根结点
int root = 1;
while (has_fa[root]) root++; //找到根结点
//递归
dfs(root);
//取两个
printf("%d
", max(f[root][0], f[root][1]));
return 0;
}