Skip to content

Commit ea860e7

Browse files
authored
feat: add solutions to lc problem: No.3108 (#2552)
No.3108.Minimum Cost Walk in Weighted Graph
1 parent b95ccf3 commit ea860e7

File tree

7 files changed

+951
-8
lines changed

7 files changed

+951
-8
lines changed

solution/3100-3199/3108.Minimum Cost Walk in Weighted Graph/README.md

+322-4
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,342 @@
7070

7171
## 解法
7272

73-
### 方法一
73+
### 方法一:贪心 + 并查集
74+
75+
我们注意到,一个正整数与其他若干个正整数不断进行“按位与”运算,结果只会越来越小。因此,为了使得旅途的代价尽可能小,我们应该将处于同一个连通分量的所有边的权值进行“按位与”运算,然后再进行查询。
76+
77+
那么,问题转化为,如何找出同一个连通份量的所有边,然后进行“按位与”运算。
78+
79+
我们可以用并查集来维护连通分量。
80+
81+
具体地,我们遍历每一条边 $(u, v, w)$,将 $u$ 和 $v$ 进行合并。然后,我们再一次遍历每一条边 $(u, v, w)$,找到 $u$ 和 $v$ 所在的连通分量的根节点 $root$,用一个数组 $g$ 记录每个连通分量的所有边的权值进行“按位与”运算的结果。
82+
83+
最后,对于每一个查询 $(s, t)$,我们首先判断 $s$ 与 $t$ 是否相等,如果相等,那么答案为 $0$,否则,我们判断 $s$ 和 $t$ 是否在同一个连通分量中,如果在同一个连通分量中,那么答案为该查询的连通分量的根节点的 $g$ 值,否则,答案为 $-1$。
84+
85+
时间复杂度 $O((n + m + q) \times \alpha(n))$,空间复杂度 $O(n)$。其中 $n$, $m$ 和 $q$ 分别表示节点数、边数和查询数,而 $\alpha(n)$ 表示 Ackermann 函数的反函数。
7486

7587
<!-- tabs:start -->
7688

7789
```python
78-
90+
class UnionFind:
91+
def __init__(self, n):
92+
self.p = list(range(n))
93+
self.size = [1] * n
94+
95+
def find(self, x):
96+
if self.p[x] != x:
97+
self.p[x] = self.find(self.p[x])
98+
return self.p[x]
99+
100+
def union(self, a, b):
101+
pa, pb = self.find(a), self.find(b)
102+
if pa == pb:
103+
return False
104+
if self.size[pa] > self.size[pb]:
105+
self.p[pb] = pa
106+
self.size[pa] += self.size[pb]
107+
else:
108+
self.p[pa] = pb
109+
self.size[pb] += self.size[pa]
110+
return True
111+
112+
113+
class Solution:
114+
def minimumCost(
115+
self, n: int, edges: List[List[int]], query: List[List[int]]
116+
) -> List[int]:
117+
g = [-1] * n
118+
uf = UnionFind(n)
119+
for u, v, _ in edges:
120+
uf.union(u, v)
121+
for u, _, w in edges:
122+
root = uf.find(u)
123+
g[root] &= w
124+
125+
def f(u: int, v: int) -> int:
126+
if u == v:
127+
return 0
128+
a, b = uf.find(u), uf.find(v)
129+
return g[a] if a == b else -1
130+
131+
return [f(s, t) for s, t in query]
79132
```
80133

81134
```java
82-
135+
class UnionFind {
136+
private final int[] p;
137+
private final int[] size;
138+
139+
public UnionFind(int n) {
140+
p = new int[n];
141+
size = new int[n];
142+
for (int i = 0; i < n; ++i) {
143+
p[i] = i;
144+
size[i] = 1;
145+
}
146+
}
147+
148+
public int find(int x) {
149+
if (p[x] != x) {
150+
p[x] = find(p[x]);
151+
}
152+
return p[x];
153+
}
154+
155+
public boolean union(int a, int b) {
156+
int pa = find(a), pb = find(b);
157+
if (pa == pb) {
158+
return false;
159+
}
160+
if (size[pa] > size[pb]) {
161+
p[pb] = pa;
162+
size[pa] += size[pb];
163+
} else {
164+
p[pa] = pb;
165+
size[pb] += size[pa];
166+
}
167+
return true;
168+
}
169+
170+
public int size(int x) {
171+
return size[find(x)];
172+
}
173+
}
174+
175+
class Solution {
176+
private UnionFind uf;
177+
private int[] g;
178+
179+
public int[] minimumCost(int n, int[][] edges, int[][] query) {
180+
uf = new UnionFind(n);
181+
for (var e : edges) {
182+
uf.union(e[0], e[1]);
183+
}
184+
g = new int[n];
185+
Arrays.fill(g, -1);
186+
for (var e : edges) {
187+
int root = uf.find(e[0]);
188+
g[root] &= e[2];
189+
}
190+
int m = query.length;
191+
int[] ans = new int[m];
192+
for (int i = 0; i < m; ++i) {
193+
int s = query[i][0], t = query[i][1];
194+
ans[i] = f(s, t);
195+
}
196+
return ans;
197+
}
198+
199+
private int f(int u, int v) {
200+
if (u == v) {
201+
return 0;
202+
}
203+
int a = uf.find(u), b = uf.find(v);
204+
return a == b ? g[a] : -1;
205+
}
206+
}
83207
```
84208

85209
```cpp
86-
210+
class UnionFind {
211+
public:
212+
UnionFind(int n) {
213+
p = vector<int>(n);
214+
size = vector<int>(n, 1);
215+
iota(p.begin(), p.end(), 0);
216+
}
217+
218+
bool unite(int a, int b) {
219+
int pa = find(a), pb = find(b);
220+
if (pa == pb) {
221+
return false;
222+
}
223+
if (size[pa] > size[pb]) {
224+
p[pb] = pa;
225+
size[pa] += size[pb];
226+
} else {
227+
p[pa] = pb;
228+
size[pb] += size[pa];
229+
}
230+
return true;
231+
}
232+
233+
int find(int x) {
234+
if (p[x] != x) {
235+
p[x] = find(p[x]);
236+
}
237+
return p[x];
238+
}
239+
240+
int getSize(int x) {
241+
return size[find(x)];
242+
}
243+
244+
private:
245+
vector<int> p, size;
246+
};
247+
248+
class Solution {
249+
public:
250+
vector<int> minimumCost(int n, vector<vector<int>>& edges, vector<vector<int>>& query) {
251+
g = vector<int>(n, -1);
252+
uf = new UnionFind(n);
253+
for (auto& e : edges) {
254+
uf->unite(e[0], e[1]);
255+
}
256+
for (auto& e : edges) {
257+
int root = uf->find(e[0]);
258+
g[root] &= e[2];
259+
}
260+
vector<int> ans;
261+
for (auto& q : query) {
262+
ans.push_back(f(q[0], q[1]));
263+
}
264+
return ans;
265+
}
266+
267+
private:
268+
UnionFind* uf;
269+
vector<int> g;
270+
271+
int f(int u, int v) {
272+
if (u == v) {
273+
return 0;
274+
}
275+
int a = uf->find(u), b = uf->find(v);
276+
return a == b ? g[a] : -1;
277+
}
278+
};
87279
```
88280
89281
```go
282+
type unionFind struct {
283+
p, size []int
284+
}
285+
286+
func newUnionFind(n int) *unionFind {
287+
p := make([]int, n)
288+
size := make([]int, n)
289+
for i := range p {
290+
p[i] = i
291+
size[i] = 1
292+
}
293+
return &unionFind{p, size}
294+
}
295+
296+
func (uf *unionFind) find(x int) int {
297+
if uf.p[x] != x {
298+
uf.p[x] = uf.find(uf.p[x])
299+
}
300+
return uf.p[x]
301+
}
302+
303+
func (uf *unionFind) union(a, b int) bool {
304+
pa, pb := uf.find(a), uf.find(b)
305+
if pa == pb {
306+
return false
307+
}
308+
if uf.size[pa] > uf.size[pb] {
309+
uf.p[pb] = pa
310+
uf.size[pa] += uf.size[pb]
311+
} else {
312+
uf.p[pa] = pb
313+
uf.size[pb] += uf.size[pa]
314+
}
315+
return true
316+
}
317+
318+
func (uf *unionFind) getSize(x int) int {
319+
return uf.size[uf.find(x)]
320+
}
321+
322+
func minimumCost(n int, edges [][]int, query [][]int) (ans []int) {
323+
uf := newUnionFind(n)
324+
g := make([]int, n)
325+
for i := range g {
326+
g[i] = -1
327+
}
328+
for _, e := range edges {
329+
uf.union(e[0], e[1])
330+
}
331+
for _, e := range edges {
332+
root := uf.find(e[0])
333+
g[root] &= e[2]
334+
}
335+
f := func(u, v int) int {
336+
if u == v {
337+
return 0
338+
}
339+
a, b := uf.find(u), uf.find(v)
340+
if a == b {
341+
return g[a]
342+
}
343+
return -1
344+
}
345+
for _, q := range query {
346+
ans = append(ans, f(q[0], q[1]))
347+
}
348+
return
349+
}
350+
```
90351

352+
```ts
353+
class UnionFind {
354+
p: number[];
355+
size: number[];
356+
constructor(n: number) {
357+
this.p = Array(n)
358+
.fill(0)
359+
.map((_, i) => i);
360+
this.size = Array(n).fill(1);
361+
}
362+
363+
find(x: number): number {
364+
if (this.p[x] !== x) {
365+
this.p[x] = this.find(this.p[x]);
366+
}
367+
return this.p[x];
368+
}
369+
370+
union(a: number, b: number): boolean {
371+
const [pa, pb] = [this.find(a), this.find(b)];
372+
if (pa === pb) {
373+
return false;
374+
}
375+
if (this.size[pa] > this.size[pb]) {
376+
this.p[pb] = pa;
377+
this.size[pa] += this.size[pb];
378+
} else {
379+
this.p[pa] = pb;
380+
this.size[pb] += this.size[pa];
381+
}
382+
return true;
383+
}
384+
385+
getSize(x: number): number {
386+
return this.size[this.find(x)];
387+
}
388+
}
389+
390+
function minimumCost(n: number, edges: number[][], query: number[][]): number[] {
391+
const uf = new UnionFind(n);
392+
const g: number[] = Array(n).fill(-1);
393+
for (const [u, v, _] of edges) {
394+
uf.union(u, v);
395+
}
396+
for (const [u, _, w] of edges) {
397+
const root = uf.find(u);
398+
g[root] &= w;
399+
}
400+
const f = (u: number, v: number): number => {
401+
if (u === v) {
402+
return 0;
403+
}
404+
const [a, b] = [uf.find(u), uf.find(v)];
405+
return a === b ? g[a] : -1;
406+
};
407+
return query.map(([u, v]) => f(u, v));
408+
}
91409
```
92410

93411
<!-- tabs:end -->

0 commit comments

Comments
 (0)