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);//从根结点开始,健康,无前驱
}
};