在acwing上学习算法的一点思考与总结
每一个节点的情况无非就两种:选和不选。那就开设两个记录答案的数组,第一个数组是选择根节点时的总高兴度,第二个是不选根节点时的总高兴度。
具体的代码就要用dfs来实现,因为dfs会先选择一条路往死里搜,搜到最后一个节点就会返回到它上一个节点,然后再去搜索它的分支。这保证了分支与分支之间不受影响。
需要注意的是在这个题中的图是有向图,区别于 树的重心那题是有向图,为了防止无限次向上递归,我们需要设置一个bool数组st[ ]来判断这个节点是否已被走过。
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 6010;
int n;
int h[N], e[N], ne[N], idx; //模拟树
int happy[N]; //录入高兴度
int f[N][2]; //存储选和不选时的高兴度
bool has_fa[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; 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]);
//不用写return,当dfs搜索完所有节点时,才会开始计算高兴度,这整个计算过程都是在for循环内执行。当返回到根节点时两种情况的高兴度都计算完,自动退出循环。
}
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &happy[i]);
memset(h, -1, sizeof h);
for (int i = 0; i < n - 1; i ++ )
{
int a, b;
scanf("%d%d", &a, &b);
add(b, a);
has_fa[a] = true; //标记为已有父节点
}
int root = 1;
while (has_fa[root]) root ++ ; //寻找根节点
dfs(root);
printf("%d\n", max(f[root][0], f[root][1])); //取两种情况最大值输出
return 0;
}