LeetCode/在树上执行操作以后得到的最大分数

有一棵 n 个节点的无向树,节点编号为 0 到 n - 1 ,根节点编号为 0 。给你一个长度为 n - 1 的二维整数数组 edges 表示这棵树,其中 edges[i] = [ai, bi] 表示树中节点 ai 和 bi 有一条边。
同时给你一个长度为 n 下标从 0 开始的整数数组 values ,其中 values[i] 表示第 i 个节点的值。
一开始你的分数为 0 ,每次操作中,你将执行:

选择节点 i ,将 values[i] 加入你的分数,将 values[i] 变为 0 。
如果从根节点出发,到任意叶子节点经过的路径上的节点值之和都不等于 0 ,那么我们称这棵树是健康的 。
你可以对这棵树执行任意次操作,但要求执行完所有操作以后树是健康的 ,请你返回你可以获得的最大分数 。

1. 动态规划树

class Solution {
public:
    long long maximumScoreAfterOperations(vector<vector<int>>& edges, vector<int>& values) {
        int n = values.size();
        vector<vector<int>> g(n);//create graph
        for (auto &e: edges) {
            int x = e[0], y = e[1];
            g[x].push_back(y);
            g[y].push_back(x);
        }

        vector<vector<long long>> memo(n,vector<long long>(2,INT_MIN));//对应节点子树健康与不健康的最大积分
        function<long long(int, bool, int)> dfs = [&](int i, bool j, int fa) -> long long {//第i个节点的子树位于状态j时子树的最大积分
            if(memo[i][j]!=INT_MIN) return memo[i][j];
            long long res1 = values[i];//当前子树不健康
            long long res2 = 0; //当前子树健康
            for (int ch: g[i]) {//遍历子节点
                if (ch == fa) continue;//跳过父节点
                res1 += dfs(ch, 0, i); // 不健康,子节点可以全选全部不健康
                res2 += dfs(ch, 1, i); // 健康,有两种方式,剔除当前节点且子树全不健康,或者子树全健康,不剔除当前节点
            }
            res2 = max(res1-values[i],res2+values[i]);
            if(g[i].size()==1&&g[i][0]==fa) res2 = 0;//叶子节点修正为0,想要健康子树值只能为0
            memo[i][0] = res1;
            memo[i][1] = res2;
            return memo[i][j];
        };
        return dfs(0, 1, -1);//从根结点开始,健康,无前驱
    }
};
posted @ 2023-11-05 16:03  失控D大白兔  阅读(12)  评论(0编辑  收藏  举报