From 3db410353b2633e7a0fc25eea3d6459fb28c78c8 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Tue, 7 Nov 2023 19:16:56 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.2925 No.2925.Maximum Score After Applying Operations on a Tree --- run_format.py | 16 +- .../README.md | 161 +++++++++++++++++- .../README_EN.md | 161 +++++++++++++++++- .../Solution.cpp | 31 ++++ .../Solution.go | 27 +++ .../Solution.java | 34 ++++ .../Solution.py | 22 +++ .../Solution.ts | 24 +++ 8 files changed, 468 insertions(+), 8 deletions(-) create mode 100644 solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.cpp create mode 100644 solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.go create mode 100644 solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.java create mode 100644 solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.py create mode 100644 solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.ts diff --git a/run_format.py b/run_format.py index 856b39b4387ae..63a2bc20b4821 100644 --- a/run_format.py +++ b/run_format.py @@ -4,9 +4,21 @@ import re import black -suffixes = ["md", "go"] +suffixes = ["md", "py", "java", "c", "cpp", "go", "php", "cs", "rs", "js", "ts", "sql"] -code_blocks = ["go"] +code_blocks = [ + "python", + "java", + "cpp", + "c", + "go", + "ts", + "js", + "php", + "cs", + "rust", + "sql", +] functions_to_replace = [ "ABS", diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README.md b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README.md index 8ab1f6d8cae91..744b595848a29 100644 --- a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README.md +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README.md @@ -69,6 +69,22 @@ +**方法一:树形 DP** + +题目实际上是让我们从树的所有节点中选出一些节点,使得这些节点的值之和最大,并且每条从根节点到叶子节点的路径上都有一个点没有被选中。 + +我们可以使用树形 DP 的方法解决这个问题。 + +我们设计一个函数 $dfs(i, fa)$,其中 $i$ 表示当前以节点 $i$ 作为子树的根节点,且 $fa$ 表示 $i$ 的父节点,函数返回一个长度为 $2$ 的数组,其中 $[0]$ 表示该子树中所有节点的值之和,而 $[1]$ 表示该子树满足每条路径上都有一个点没有被选中的最大值。 + +其中 $[0]$ 的值可以直接通过 DFS 累加每个节点的值得到,而 $[1]$ 的值,则需要考虑两种情况,即节点 $i$ 是否被选中。如果被选中,那么节点 $i$ 的每个子树得必须满足每条路径上都有一个点没有被选中;如果没有被选中,那么节点 $i$ 的每个子树可以选取所有节点。我们取这两种情况中的最大值即可。 + +需要注意的是,叶子节点的 $[1]$ 的值为 $0$,因为叶子节点没有子树,所以不需要考虑每条路径上都有一个点没有被选中的情况。 + +答案为 $dfs(0, -1)[1]$。 + +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为节点数。 + ### **Python3** @@ -76,7 +92,28 @@ ```python - +class Solution: + def maximumScoreAfterOperations( + self, edges: List[List[int]], values: List[int] + ) -> int: + def dfs(i: int, fa: int = -1) -> (int, int): + a = b = 0 + leaf = True + for j in g[i]: + if j != fa: + leaf = False + aa, bb = dfs(j, i) + a += aa + b += bb + if leaf: + return values[i], 0 + return values[i] + a, max(values[i] + b, a) + + g = [[] for _ in range(len(values))] + for a, b in edges: + g[a].append(b) + g[b].append(a) + return dfs(0)[1] ``` ### **Java** @@ -84,19 +121,137 @@ ```java - +class Solution { + private List[] g; + private int[] values; + + public long maximumScoreAfterOperations(int[][] edges, int[] values) { + int n = values.length; + g = new List[n]; + this.values = values; + Arrays.setAll(g, k -> new ArrayList<>()); + for (var e : edges) { + int a = e[0], b = e[1]; + g[a].add(b); + g[b].add(a); + } + return dfs(0, -1)[1]; + } + + private long[] dfs(int i, int fa) { + long a = 0, b = 0; + boolean leaf = true; + for (int j : g[i]) { + if (j != fa) { + leaf = false; + var t = dfs(j, i); + a += t[0]; + b += t[1]; + } + } + if (leaf) { + return new long[] {values[i], 0}; + } + return new long[] {values[i] + a, Math.max(values[i] + b, a)}; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + long long maximumScoreAfterOperations(vector>& edges, vector& values) { + int n = values.size(); + vector g[n]; + for (auto& e : edges) { + int a = e[0], b = e[1]; + g[a].emplace_back(b); + g[b].emplace_back(a); + } + using ll = long long; + function(int, int)> dfs = [&](int i, int fa) -> pair { + ll a = 0, b = 0; + bool leaf = true; + for (int j : g[i]) { + if (j != fa) { + auto [aa, bb] = dfs(j, i); + a += aa; + b += bb; + leaf = false; + } + } + if (leaf) { + return {values[i], 0LL}; + } + return {values[i] + a, max(values[i] + b, a)}; + }; + auto [_, b] = dfs(0, -1); + return b; + } +}; ``` ### **Go** ```go +func maximumScoreAfterOperations(edges [][]int, values []int) int64 { + g := make([][]int, len(values)) + for _, e := range edges { + a, b := e[0], e[1] + g[a] = append(g[a], b) + g[b] = append(g[b], a) + } + var dfs func(int, int) (int64, int64) + dfs = func(i, fa int) (int64, int64) { + a, b := int64(0), int64(0) + leaf := true + for _, j := range g[i] { + if j != fa { + leaf = false + aa, bb := dfs(j, i) + a += aa + b += bb + } + } + if leaf { + return int64(values[i]), int64(0) + } + return int64(values[i]) + a, max(int64(values[i])+b, a) + } + _, b := dfs(0, -1) + return b +} +``` +### **TypeScript** + +```ts +function maximumScoreAfterOperations(edges: number[][], values: number[]): number { + const g: number[][] = Array.from({ length: values.length }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + g[b].push(a); + } + const dfs = (i: number, fa: number): [number, number] => { + let [a, b] = [0, 0]; + let leaf = true; + for (const j of g[i]) { + if (j !== fa) { + const [aa, bb] = dfs(j, i); + a += aa; + b += bb; + leaf = false; + } + } + if (leaf) { + return [values[i], 0]; + } + return [values[i] + a, Math.max(values[i] + b, a)]; + }; + return dfs(0, -1)[1]; +} ``` ### **...** diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README_EN.md b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README_EN.md index e471b7bfda94f..5039c19d821f6 100644 --- a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README_EN.md +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/README_EN.md @@ -59,30 +59,185 @@ It can be shown that 40 is the maximum score obtainable after any number of oper ## Solutions +**Solution 1: Tree DP** + +The problem is actually asking us to select some nodes from all nodes of the tree so that the sum of these nodes' values is maximized, and there is one node on each path from the root node to the leaf node that is not selected. + +We can use the method of tree DP to solve this problem. + +We design a function $dfs(i, fa)$, where $i$ represents the current node with node $i$ as the root of the subtree, and $fa$ represents the parent node of $i$. The function returns an array of length $2$, where $[0]$ represents the sum of the values of all nodes in the subtree, and $[1]$ represents the maximum value of the subtree satisfying that there is one node not selected on each path. + +The value of $[0]$ can be obtained directly by DFS accumulating the values of each node, while the value of $[1]$ needs to consider two situations, namely whether node $i$ is selected. If it is selected, then each subtree of node $i$ must satisfy that there is one node not selected on each path; if it is not selected, then all nodes of each subtree of node $i$ can be selected. We take the maximum of these two situations. + +It should be noted that the value of $[1]$ of the leaf node is $0$, because the leaf node has no subtree, so there is no need to consider the situation where there is one node not selected on each path. + +The answer is $dfs(0, -1)[1]$. + +The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the number of nodes. + ### **Python3** ```python - +class Solution: + def maximumScoreAfterOperations( + self, edges: List[List[int]], values: List[int] + ) -> int: + def dfs(i: int, fa: int = -1) -> (int, int): + a = b = 0 + leaf = True + for j in g[i]: + if j != fa: + leaf = False + aa, bb = dfs(j, i) + a += aa + b += bb + if leaf: + return values[i], 0 + return values[i] + a, max(values[i] + b, a) + + g = [[] for _ in range(len(values))] + for a, b in edges: + g[a].append(b) + g[b].append(a) + return dfs(0)[1] ``` ### **Java** ```java - +class Solution { + private List[] g; + private int[] values; + + public long maximumScoreAfterOperations(int[][] edges, int[] values) { + int n = values.length; + g = new List[n]; + this.values = values; + Arrays.setAll(g, k -> new ArrayList<>()); + for (var e : edges) { + int a = e[0], b = e[1]; + g[a].add(b); + g[b].add(a); + } + return dfs(0, -1)[1]; + } + + private long[] dfs(int i, int fa) { + long a = 0, b = 0; + boolean leaf = true; + for (int j : g[i]) { + if (j != fa) { + leaf = false; + var t = dfs(j, i); + a += t[0]; + b += t[1]; + } + } + if (leaf) { + return new long[] {values[i], 0}; + } + return new long[] {values[i] + a, Math.max(values[i] + b, a)}; + } +} ``` ### **C++** ```cpp - +class Solution { +public: + long long maximumScoreAfterOperations(vector>& edges, vector& values) { + int n = values.size(); + vector g[n]; + for (auto& e : edges) { + int a = e[0], b = e[1]; + g[a].emplace_back(b); + g[b].emplace_back(a); + } + using ll = long long; + function(int, int)> dfs = [&](int i, int fa) -> pair { + ll a = 0, b = 0; + bool leaf = true; + for (int j : g[i]) { + if (j != fa) { + auto [aa, bb] = dfs(j, i); + a += aa; + b += bb; + leaf = false; + } + } + if (leaf) { + return {values[i], 0LL}; + } + return {values[i] + a, max(values[i] + b, a)}; + }; + auto [_, b] = dfs(0, -1); + return b; + } +}; ``` ### **Go** ```go +func maximumScoreAfterOperations(edges [][]int, values []int) int64 { + g := make([][]int, len(values)) + for _, e := range edges { + a, b := e[0], e[1] + g[a] = append(g[a], b) + g[b] = append(g[b], a) + } + var dfs func(int, int) (int64, int64) + dfs = func(i, fa int) (int64, int64) { + a, b := int64(0), int64(0) + leaf := true + for _, j := range g[i] { + if j != fa { + leaf = false + aa, bb := dfs(j, i) + a += aa + b += bb + } + } + if leaf { + return int64(values[i]), int64(0) + } + return int64(values[i]) + a, max(int64(values[i])+b, a) + } + _, b := dfs(0, -1) + return b +} +``` +### **TypeScript** + +```ts +function maximumScoreAfterOperations(edges: number[][], values: number[]): number { + const g: number[][] = Array.from({ length: values.length }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + g[b].push(a); + } + const dfs = (i: number, fa: number): [number, number] => { + let [a, b] = [0, 0]; + let leaf = true; + for (const j of g[i]) { + if (j !== fa) { + const [aa, bb] = dfs(j, i); + a += aa; + b += bb; + leaf = false; + } + } + if (leaf) { + return [values[i], 0]; + } + return [values[i] + a, Math.max(values[i] + b, a)]; + }; + return dfs(0, -1)[1]; +} ``` ### **...** diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.cpp b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.cpp new file mode 100644 index 0000000000000..af97b58de4619 --- /dev/null +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.cpp @@ -0,0 +1,31 @@ +class Solution { +public: + long long maximumScoreAfterOperations(vector>& edges, vector& values) { + int n = values.size(); + vector g[n]; + for (auto& e : edges) { + int a = e[0], b = e[1]; + g[a].emplace_back(b); + g[b].emplace_back(a); + } + using ll = long long; + function(int, int)> dfs = [&](int i, int fa) -> pair { + ll a = 0, b = 0; + bool leaf = true; + for (int j : g[i]) { + if (j != fa) { + auto [aa, bb] = dfs(j, i); + a += aa; + b += bb; + leaf = false; + } + } + if (leaf) { + return {values[i], 0LL}; + } + return {values[i] + a, max(values[i] + b, a)}; + }; + auto [_, b] = dfs(0, -1); + return b; + } +}; \ No newline at end of file diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.go b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.go new file mode 100644 index 0000000000000..620386deb4f07 --- /dev/null +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.go @@ -0,0 +1,27 @@ +func maximumScoreAfterOperations(edges [][]int, values []int) int64 { + g := make([][]int, len(values)) + for _, e := range edges { + a, b := e[0], e[1] + g[a] = append(g[a], b) + g[b] = append(g[b], a) + } + var dfs func(int, int) (int64, int64) + dfs = func(i, fa int) (int64, int64) { + a, b := int64(0), int64(0) + leaf := true + for _, j := range g[i] { + if j != fa { + leaf = false + aa, bb := dfs(j, i) + a += aa + b += bb + } + } + if leaf { + return int64(values[i]), int64(0) + } + return int64(values[i]) + a, max(int64(values[i])+b, a) + } + _, b := dfs(0, -1) + return b +} \ No newline at end of file diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.java b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.java new file mode 100644 index 0000000000000..240a0519d0bec --- /dev/null +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.java @@ -0,0 +1,34 @@ +class Solution { + private List[] g; + private int[] values; + + public long maximumScoreAfterOperations(int[][] edges, int[] values) { + int n = values.length; + g = new List[n]; + this.values = values; + Arrays.setAll(g, k -> new ArrayList<>()); + for (var e : edges) { + int a = e[0], b = e[1]; + g[a].add(b); + g[b].add(a); + } + return dfs(0, -1)[1]; + } + + private long[] dfs(int i, int fa) { + long a = 0, b = 0; + boolean leaf = true; + for (int j : g[i]) { + if (j != fa) { + leaf = false; + var t = dfs(j, i); + a += t[0]; + b += t[1]; + } + } + if (leaf) { + return new long[] {values[i], 0}; + } + return new long[] {values[i] + a, Math.max(values[i] + b, a)}; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.py b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.py new file mode 100644 index 0000000000000..cf52956ced0cb --- /dev/null +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.py @@ -0,0 +1,22 @@ +class Solution: + def maximumScoreAfterOperations( + self, edges: List[List[int]], values: List[int] + ) -> int: + def dfs(i: int, fa: int = -1) -> (int, int): + a = b = 0 + leaf = True + for j in g[i]: + if j != fa: + leaf = False + aa, bb = dfs(j, i) + a += aa + b += bb + if leaf: + return values[i], 0 + return values[i] + a, max(values[i] + b, a) + + g = [[] for _ in range(len(values))] + for a, b in edges: + g[a].append(b) + g[b].append(a) + return dfs(0)[1] diff --git a/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.ts b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.ts new file mode 100644 index 0000000000000..28c4b235cfdbb --- /dev/null +++ b/solution/2900-2999/2925.Maximum Score After Applying Operations on a Tree/Solution.ts @@ -0,0 +1,24 @@ +function maximumScoreAfterOperations(edges: number[][], values: number[]): number { + const g: number[][] = Array.from({ length: values.length }, () => []); + for (const [a, b] of edges) { + g[a].push(b); + g[b].push(a); + } + const dfs = (i: number, fa: number): [number, number] => { + let [a, b] = [0, 0]; + let leaf = true; + for (const j of g[i]) { + if (j !== fa) { + const [aa, bb] = dfs(j, i); + a += aa; + b += bb; + leaf = false; + } + } + if (leaf) { + return [values[i], 0]; + } + return [values[i] + a, Math.max(values[i] + b, a)]; + }; + return dfs(0, -1)[1]; +}