题目传送门

一、题目分析

状态表示
\(f[u][1]\)表示以\(u\)为根节点的子树并且包括\(u\)总快乐指数

\(f[u][0]\)表示以\(u\)为根节点并且不包括\(u\)总快乐指数

状态计算
要想求得一棵以\(u\)为根节点的子树的最大指数分为两种:选\(u\)节点或不选\(u\)节点

记点\(u\)的子节点是\(j\)

  • 1.选\(u\)\(f[u][1]=Σf[j][0]\)
  • 2.不选\(u\)\(f[u][0]=Σmax(f[j][1],f[j][0])\)

记根节点为\(root\)
\(root\)开始\(dfs\)一遍即可
最后输出\(max(f[root][1],f[root][0])\)

可以参阅它的姊妹题 AcWing 323 . 战略游戏

二、实现代码

#include <bits/stdc++.h>

using namespace std;
const int N = 6010;
int h[N], e[N], ne[N], idx;
int happy[N];   //快乐值
bool st[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 = 1; i <= n - 1; i++) {
        int x, y;
        cin >> x >> y;
        add(y, x);
        st[x] = true;
    }
    //从1开始找根结点
    int root = 1;
    while (st[root]) root++; //找到根结点
    //递归
    dfs(root);
    //取两个
    printf("%d\n", max(f[root][0], f[root][1]));
    return 0;
}

相关文章:

  • 2021-07-06
  • 2022-12-23
  • 2022-12-23
  • 2021-12-21
  • 2021-12-31
  • 2021-07-21
猜你喜欢
  • 2022-01-13
  • 2022-01-04
  • 2021-12-01
相关资源
相似解决方案