From 7b1b020669ab5b3e462efcf6ca5b3207d50d513e Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sun, 7 Apr 2024 19:53:37 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.3108 No.3108.Minimum Cost Walk in Weighted Graph --- .../README.md | 326 +++++++++++++++++- .../README_EN.md | 326 +++++++++++++++++- .../Solution.cpp | 69 ++++ .../Solution.go | 68 ++++ .../Solution.java | 72 ++++ .../Solution.py | 42 +++ .../Solution.ts | 56 +++ 7 files changed, 951 insertions(+), 8 deletions(-) create mode 100644 solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.cpp create mode 100644 solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.go create mode 100644 solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.java create mode 100644 solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.py create mode 100644 solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.ts diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README.md b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README.md index f9d6c24ae5658..4d596b2dcac86 100644 --- a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README.md +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README.md @@ -70,24 +70,342 @@ ## 解法 -### 方法一 +### 方法一:贪心 + 并查集 + +我们注意到,一个正整数与其他若干个正整数不断进行“按位与”运算,结果只会越来越小。因此,为了使得旅途的代价尽可能小,我们应该将处于同一个连通分量的所有边的权值进行“按位与”运算,然后再进行查询。 + +那么,问题转化为,如何找出同一个连通份量的所有边,然后进行“按位与”运算。 + +我们可以用并查集来维护连通分量。 + +具体地,我们遍历每一条边 $(u, v, w)$,将 $u$ 和 $v$ 进行合并。然后,我们再一次遍历每一条边 $(u, v, w)$,找到 $u$ 和 $v$ 所在的连通分量的根节点 $root$,用一个数组 $g$ 记录每个连通分量的所有边的权值进行“按位与”运算的结果。 + +最后,对于每一个查询 $(s, t)$,我们首先判断 $s$ 与 $t$ 是否相等,如果相等,那么答案为 $0$,否则,我们判断 $s$ 和 $t$ 是否在同一个连通分量中,如果在同一个连通分量中,那么答案为该查询的连通分量的根节点的 $g$ 值,否则,答案为 $-1$。 + +时间复杂度 $O((n + m + q) \times \alpha(n))$,空间复杂度 $O(n)$。其中 $n$, $m$ 和 $q$ 分别表示节点数、边数和查询数,而 $\alpha(n)$ 表示 Ackermann 函数的反函数。 ```python - +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + +class Solution: + def minimumCost( + self, n: int, edges: List[List[int]], query: List[List[int]] + ) -> List[int]: + g = [-1] * n + uf = UnionFind(n) + for u, v, _ in edges: + uf.union(u, v) + for u, _, w in edges: + root = uf.find(u) + g[root] &= w + + def f(u: int, v: int) -> int: + if u == v: + return 0 + a, b = uf.find(u), uf.find(v) + return g[a] if a == b else -1 + + return [f(s, t) for s, t in query] ``` ```java - +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { + p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + public int size(int x) { + return size[find(x)]; + } +} + +class Solution { + private UnionFind uf; + private int[] g; + + public int[] minimumCost(int n, int[][] edges, int[][] query) { + uf = new UnionFind(n); + for (var e : edges) { + uf.union(e[0], e[1]); + } + g = new int[n]; + Arrays.fill(g, -1); + for (var e : edges) { + int root = uf.find(e[0]); + g[root] &= e[2]; + } + int m = query.length; + int[] ans = new int[m]; + for (int i = 0; i < m; ++i) { + int s = query[i][0], t = query[i][1]; + ans[i] = f(s, t); + } + return ans; + } + + private int f(int u, int v) { + if (u == v) { + return 0; + } + int a = uf.find(u), b = uf.find(v); + return a == b ? g[a] : -1; + } +} ``` ```cpp - +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + int getSize(int x) { + return size[find(x)]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector minimumCost(int n, vector>& edges, vector>& query) { + g = vector(n, -1); + uf = new UnionFind(n); + for (auto& e : edges) { + uf->unite(e[0], e[1]); + } + for (auto& e : edges) { + int root = uf->find(e[0]); + g[root] &= e[2]; + } + vector ans; + for (auto& q : query) { + ans.push_back(f(q[0], q[1])); + } + return ans; + } + +private: + UnionFind* uf; + vector g; + + int f(int u, int v) { + if (u == v) { + return 0; + } + int a = uf->find(u), b = uf->find(v); + return a == b ? g[a] : -1; + } +}; ``` ```go +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) + for i := range p { + p[i] = i + size[i] = 1 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) + } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] + } + return true +} + +func (uf *unionFind) getSize(x int) int { + return uf.size[uf.find(x)] +} + +func minimumCost(n int, edges [][]int, query [][]int) (ans []int) { + uf := newUnionFind(n) + g := make([]int, n) + for i := range g { + g[i] = -1 + } + for _, e := range edges { + uf.union(e[0], e[1]) + } + for _, e := range edges { + root := uf.find(e[0]) + g[root] &= e[2] + } + f := func(u, v int) int { + if u == v { + return 0 + } + a, b := uf.find(u), uf.find(v) + if a == b { + return g[a] + } + return -1 + } + for _, q := range query { + ans = append(ans, f(q[0], q[1])) + } + return +} +``` +```ts +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), this.find(b)]; + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + getSize(x: number): number { + return this.size[this.find(x)]; + } +} + +function minimumCost(n: number, edges: number[][], query: number[][]): number[] { + const uf = new UnionFind(n); + const g: number[] = Array(n).fill(-1); + for (const [u, v, _] of edges) { + uf.union(u, v); + } + for (const [u, _, w] of edges) { + const root = uf.find(u); + g[root] &= w; + } + const f = (u: number, v: number): number => { + if (u === v) { + return 0; + } + const [a, b] = [uf.find(u), uf.find(v)]; + return a === b ? g[a] : -1; + }; + return query.map(([u, v]) => f(u, v)); +} ``` diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README_EN.md b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README_EN.md index 316a077b89b0c..be8b89cad3d21 100644 --- a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README_EN.md +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README_EN.md @@ -62,24 +62,342 @@ ## Solutions -### Solution 1 +### Solution 1: Greedy + Union Find + +We note that a positive integer performing bitwise AND operation with several other positive integers will only get smaller. Therefore, to minimize the cost of the journey, we should perform bitwise AND operation on the weights of all edges in the same connected component, and then perform the query. + +So, the problem is transformed into how to find all the edges in the same connected component and perform bitwise AND operation. + +We can use a union-find set to maintain the connected components. + +Specifically, we traverse each edge $(u, v, w)$ and merge $u$ and $v$. Then, we traverse each edge $(u, v, w)$ again, find the root node $root$ of the connected component where $u$ and $v$ are located, and use an array $g$ to record the result of the bitwise AND operation of the weights of all edges in each connected component. + +Finally, for each query $(s, t)$, we first judge whether $s$ equals $t$. If they are equal, the answer is $0$. Otherwise, we judge whether $s$ and $t$ are in the same connected component. If they are in the same connected component, the answer is the $g$ value of the root node of the connected component of this query. Otherwise, the answer is $-1$. + +The time complexity is $O((n + m + q) \times \alpha(n))$, and the space complexity is $O(n)$. Here, $n$, $m$, and $q$ represent the number of nodes, edges, and queries, respectively, and $\alpha(n)$ represents the inverse function of the Ackermann function. ```python - +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + +class Solution: + def minimumCost( + self, n: int, edges: List[List[int]], query: List[List[int]] + ) -> List[int]: + g = [-1] * n + uf = UnionFind(n) + for u, v, _ in edges: + uf.union(u, v) + for u, _, w in edges: + root = uf.find(u) + g[root] &= w + + def f(u: int, v: int) -> int: + if u == v: + return 0 + a, b = uf.find(u), uf.find(v) + return g[a] if a == b else -1 + + return [f(s, t) for s, t in query] ``` ```java - +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { + p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + public int size(int x) { + return size[find(x)]; + } +} + +class Solution { + private UnionFind uf; + private int[] g; + + public int[] minimumCost(int n, int[][] edges, int[][] query) { + uf = new UnionFind(n); + for (var e : edges) { + uf.union(e[0], e[1]); + } + g = new int[n]; + Arrays.fill(g, -1); + for (var e : edges) { + int root = uf.find(e[0]); + g[root] &= e[2]; + } + int m = query.length; + int[] ans = new int[m]; + for (int i = 0; i < m; ++i) { + int s = query[i][0], t = query[i][1]; + ans[i] = f(s, t); + } + return ans; + } + + private int f(int u, int v) { + if (u == v) { + return 0; + } + int a = uf.find(u), b = uf.find(v); + return a == b ? g[a] : -1; + } +} ``` ```cpp - +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + int getSize(int x) { + return size[find(x)]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector minimumCost(int n, vector>& edges, vector>& query) { + g = vector(n, -1); + uf = new UnionFind(n); + for (auto& e : edges) { + uf->unite(e[0], e[1]); + } + for (auto& e : edges) { + int root = uf->find(e[0]); + g[root] &= e[2]; + } + vector ans; + for (auto& q : query) { + ans.push_back(f(q[0], q[1])); + } + return ans; + } + +private: + UnionFind* uf; + vector g; + + int f(int u, int v) { + if (u == v) { + return 0; + } + int a = uf->find(u), b = uf->find(v); + return a == b ? g[a] : -1; + } +}; ``` ```go +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) + for i := range p { + p[i] = i + size[i] = 1 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) + } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] + } + return true +} + +func (uf *unionFind) getSize(x int) int { + return uf.size[uf.find(x)] +} + +func minimumCost(n int, edges [][]int, query [][]int) (ans []int) { + uf := newUnionFind(n) + g := make([]int, n) + for i := range g { + g[i] = -1 + } + for _, e := range edges { + uf.union(e[0], e[1]) + } + for _, e := range edges { + root := uf.find(e[0]) + g[root] &= e[2] + } + f := func(u, v int) int { + if u == v { + return 0 + } + a, b := uf.find(u), uf.find(v) + if a == b { + return g[a] + } + return -1 + } + for _, q := range query { + ans = append(ans, f(q[0], q[1])) + } + return +} +``` +```ts +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), this.find(b)]; + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + getSize(x: number): number { + return this.size[this.find(x)]; + } +} + +function minimumCost(n: number, edges: number[][], query: number[][]): number[] { + const uf = new UnionFind(n); + const g: number[] = Array(n).fill(-1); + for (const [u, v, _] of edges) { + uf.union(u, v); + } + for (const [u, _, w] of edges) { + const root = uf.find(u); + g[root] &= w; + } + const f = (u: number, v: number): number => { + if (u === v) { + return 0; + } + const [a, b] = [uf.find(u), uf.find(v)]; + return a === b ? g[a] : -1; + }; + return query.map(([u, v]) => f(u, v)); +} ``` diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.cpp b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.cpp new file mode 100644 index 0000000000000..f489039d8c207 --- /dev/null +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.cpp @@ -0,0 +1,69 @@ +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + int getSize(int x) { + return size[find(x)]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector minimumCost(int n, vector>& edges, vector>& query) { + g = vector(n, -1); + uf = new UnionFind(n); + for (auto& e : edges) { + uf->unite(e[0], e[1]); + } + for (auto& e : edges) { + int root = uf->find(e[0]); + g[root] &= e[2]; + } + vector ans; + for (auto& q : query) { + ans.push_back(f(q[0], q[1])); + } + return ans; + } + +private: + UnionFind* uf; + vector g; + + int f(int u, int v) { + if (u == v) { + return 0; + } + int a = uf->find(u), b = uf->find(v); + return a == b ? g[a] : -1; + } +}; \ No newline at end of file diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.go b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.go new file mode 100644 index 0000000000000..c4cca157bc33a --- /dev/null +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.go @@ -0,0 +1,68 @@ +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { + p := make([]int, n) + size := make([]int, n) + for i := range p { + p[i] = i + size[i] = 1 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) + } + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false + } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] + } + return true +} + +func (uf *unionFind) getSize(x int) int { + return uf.size[uf.find(x)] +} + +func minimumCost(n int, edges [][]int, query [][]int) (ans []int) { + uf := newUnionFind(n) + g := make([]int, n) + for i := range g { + g[i] = -1 + } + for _, e := range edges { + uf.union(e[0], e[1]) + } + for _, e := range edges { + root := uf.find(e[0]) + g[root] &= e[2] + } + f := func(u, v int) int { + if u == v { + return 0 + } + a, b := uf.find(u), uf.find(v) + if a == b { + return g[a] + } + return -1 + } + for _, q := range query { + ans = append(ans, f(q[0], q[1])) + } + return +} \ No newline at end of file diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.java b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.java new file mode 100644 index 0000000000000..14020f1cf542e --- /dev/null +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.java @@ -0,0 +1,72 @@ +class UnionFind { + private final int[] p; + private final int[] size; + + public UnionFind(int n) { + p = new int[n]; + size = new int[n]; + for (int i = 0; i < n; ++i) { + p[i] = i; + size[i] = 1; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; + } + + public int size(int x) { + return size[find(x)]; + } +} + +class Solution { + private UnionFind uf; + private int[] g; + + public int[] minimumCost(int n, int[][] edges, int[][] query) { + uf = new UnionFind(n); + for (var e : edges) { + uf.union(e[0], e[1]); + } + g = new int[n]; + Arrays.fill(g, -1); + for (var e : edges) { + int root = uf.find(e[0]); + g[root] &= e[2]; + } + int m = query.length; + int[] ans = new int[m]; + for (int i = 0; i < m; ++i) { + int s = query[i][0], t = query[i][1]; + ans[i] = f(s, t); + } + return ans; + } + + private int f(int u, int v) { + if (u == v) { + return 0; + } + int a = uf.find(u), b = uf.find(v); + return a == b ? g[a] : -1; + } +} \ No newline at end of file diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.py b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.py new file mode 100644 index 0000000000000..4f0499e83895d --- /dev/null +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.py @@ -0,0 +1,42 @@ +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + +class Solution: + def minimumCost( + self, n: int, edges: List[List[int]], query: List[List[int]] + ) -> List[int]: + g = [-1] * n + uf = UnionFind(n) + for u, v, _ in edges: + uf.union(u, v) + for u, _, w in edges: + root = uf.find(u) + g[root] &= w + + def f(u: int, v: int) -> int: + if u == v: + return 0 + a, b = uf.find(u), uf.find(v) + return g[a] if a == b else -1 + + return [f(s, t) for s, t in query] diff --git a/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.ts b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.ts new file mode 100644 index 0000000000000..9f26b621ed8b2 --- /dev/null +++ b/solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/Solution.ts @@ -0,0 +1,56 @@ +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), this.find(b)]; + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + getSize(x: number): number { + return this.size[this.find(x)]; + } +} + +function minimumCost(n: number, edges: number[][], query: number[][]): number[] { + const uf = new UnionFind(n); + const g: number[] = Array(n).fill(-1); + for (const [u, v, _] of edges) { + uf.union(u, v); + } + for (const [u, _, w] of edges) { + const root = uf.find(u); + g[root] &= w; + } + const f = (u: number, v: number): number => { + if (u === v) { + return 0; + } + const [a, b] = [uf.find(u), uf.find(v)]; + return a === b ? g[a] : -1; + }; + return query.map(([u, v]) => f(u, v)); +}