Skip to content

Commit 18ea288

Browse files
committed
feat: add rust solution to lc problem: No.3778
1 parent d6298fb commit 18ea288

File tree

3 files changed

+217
-2
lines changed

3 files changed

+217
-2
lines changed

solution/3700-3799/3778.Minimum Distance Excluding One Maximum Weighted Edge/README.md

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,27 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3700-3799/3778.Mi
9090

9191
<!-- solution:start -->
9292

93-
### 方法一
93+
### 方法一:Dijkstra 算法
94+
95+
题目实际上等价于从节点 $0$ 到节点 $n-1$ 寻找一条路径,可以有一次机会将经过的某条边的权重视为 $0$,使得路径权重和最小。
96+
97+
我们首先将 $\textit{edges}$ 转化为邻接表 $\textit{g}$,其中 $\textit{g}[u]$ 存储所有与节点 $u$ 相连的边 $(v, w)$,表示节点 $u$ 与节点 $v$ 之间有一条权重为 $w$ 的边。
98+
99+
接下来,我们使用 Dijkstra 算法来寻找最短路径。我们定义一个二维数组 $\textit{dist}$,其中 $\textit{dist}[u][0]$ 表示从节点 $0$ 到节点 $u$ 的路径权重和的最小值,且没有使用将某条边权重视为 $0$ 的机会;$\textit{dist}[u][1]$ 表示从节点 $0$ 到节点 $u$ 的路径权重和的最小值,且已经使用了将某条边权重视为 $0$ 的机会。
100+
101+
我们使用一个优先队列 $\textit{pq}$ 来存储待处理的节点,初始时将 $(0, 0, 0)$ 入队,表示从节点 $0$ 出发,当前路径权重和为 $0$,且没有使用机会。
102+
103+
在每次迭代中,我们从优先队列中取出路径权重和最小的节点 $(\textit{cur}, u, \textit{used})$。如果当前路径权重和 $\textit{cur}$ 大于 $\textit{dist}[u][\textit{used}]$,则跳过该节点。
104+
105+
如果当前节点 $u$ 是节点 $n-1$ 且已经使用了机会 $\textit{used} = 1$,则返回当前路径权重和 $\textit{cur}$。
106+
107+
对于节点 $u$ 的每一条边 $(v, w)$,我们计算不使用机会的情况下到达节点 $v$ 的路径权重和 $\textit{nxt} = \textit{cur} + w$。如果 $\textit{nxt} < \textit{dist}[v][\textit{used}]$,则更新 $\textit{dist}[v][\textit{used}]$ 并将 $(\textit{nxt}, v, \textit{used})$ 入队。
108+
109+
如果当前还没有使用机会 $\textit{used} = 0$,则计算使用机会的情况下到达节点 $v$ 的路径权重和 $\textit{nxt} = \textit{cur}$。如果 $\textit{nxt} < \textit{dist}[v][1]$,则更新 $\textit{dist}[v][1]$ 并将 $(\textit{nxt}, v, 1)$ 入队。
110+
111+
遍历结束后,返回 $\textit{dist}[n-1][1]$ 即为答案。
112+
113+
时间复杂度 $O(m \times \log n)$,空间复杂度 $O(n + m)$,其中 $n$ 和 $m$ 分别是节点数和边数。
94114

95115
<!-- tabs:start -->
96116

@@ -360,6 +380,66 @@ function minCostExcludingMax(n: number, edges: number[][]): number {
360380
}
361381
```
362382

383+
#### Rust
384+
385+
```rust
386+
use std::cmp::Reverse;
387+
use std::collections::BinaryHeap;
388+
389+
impl Solution {
390+
pub fn min_cost_excluding_max(n: i32, edges: Vec<Vec<i32>>) -> i64 {
391+
let n = n as usize;
392+
393+
let mut g: Vec<Vec<(usize, i64)>> = vec![Vec::new(); n];
394+
for e in edges {
395+
let u = e[0] as usize;
396+
let v = e[1] as usize;
397+
let w = e[2] as i64;
398+
g[u].push((v, w));
399+
g[v].push((u, w));
400+
}
401+
402+
let inf: i64 = i64::MAX / 4;
403+
let mut dist = vec![[inf; 2]; n];
404+
dist[0][0] = 0;
405+
406+
// (cur_cost, node, used)
407+
let mut pq = BinaryHeap::new();
408+
pq.push(Reverse((0_i64, 0_usize, 0_usize)));
409+
410+
while let Some(Reverse((cur, u, used))) = pq.pop() {
411+
if cur > dist[u][used] {
412+
continue;
413+
}
414+
415+
if u == n - 1 && used == 1 {
416+
return cur;
417+
}
418+
419+
for &(v, w) in &g[u] {
420+
// normal edge
421+
let nxt = cur + w;
422+
if nxt < dist[v][used] {
423+
dist[v][used] = nxt;
424+
pq.push(Reverse((nxt, v, used)));
425+
}
426+
427+
// skip max edge (only once)
428+
if used == 0 {
429+
let nxt = cur;
430+
if nxt < dist[v][1] {
431+
dist[v][1] = nxt;
432+
pq.push(Reverse((nxt, v, 1)));
433+
}
434+
}
435+
}
436+
}
437+
438+
dist[n - 1][1]
439+
}
440+
}
441+
```
442+
363443
<!-- tabs:end -->
364444

365445
<!-- solution:end -->

solution/3700-3799/3778.Minimum Distance Excluding One Maximum Weighted Edge/README_EN.md

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,27 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3700-3799/3778.Mi
8888

8989
<!-- solution:start -->
9090

91-
### Solution 1
91+
### Solution 1: Dijkstra's Algorithm
92+
93+
The problem is essentially equivalent to finding a path from node $0$ to node $n-1$, where we have one opportunity to treat the weight of a traversed edge as $0$, in order to minimize the sum of path weights.
94+
95+
We first convert $\textit{edges}$ into an adjacency list $\textit{g}$, where $\textit{g}[u]$ stores all edges $(v, w)$ connected to node $u$, indicating that there is an edge with weight $w$ between node $u$ and node $v$.
96+
97+
Next, we use Dijkstra's algorithm to find the shortest path. We define a 2D array $\textit{dist}$, where $\textit{dist}[u][0]$ represents the minimum sum of path weights from node $0$ to node $u$ without using the opportunity to treat an edge weight as $0$; $\textit{dist}[u][1]$ represents the minimum sum of path weights from node $0$ to node $u$ having already used the opportunity to treat an edge weight as $0$.
98+
99+
We use a priority queue $\textit{pq}$ to store pending nodes. Initially, we enqueue $(0, 0, 0)$, indicating that we start from node $0$, with a current path weight sum of $0$, and haven't used the opportunity.
100+
101+
In each iteration, we dequeue the node $(\textit{cur}, u, \textit{used})$ with the minimum path weight sum from the priority queue. If the current path weight sum $\textit{cur}$ is greater than $\textit{dist}[u][\textit{used}]$, we skip this node.
102+
103+
If the current node $u$ is node $n-1$ and we have already used the opportunity $\textit{used} = 1$, we return the current path weight sum $\textit{cur}$.
104+
105+
For each edge $(v, w)$ of node $u$, we calculate the path weight sum to reach node $v$ without using the opportunity: $\textit{nxt} = \textit{cur} + w$. If $\textit{nxt} < \textit{dist}[v][\textit{used}]$, we update $\textit{dist}[v][\textit{used}]$ and enqueue $(\textit{nxt}, v, \textit{used})$.
106+
107+
If we haven't used the opportunity yet $\textit{used} = 0$, we calculate the path weight sum to reach node $v$ when using the opportunity: $\textit{nxt} = \textit{cur}$. If $\textit{nxt} < \textit{dist}[v][1]$, we update $\textit{dist}[v][1]$ and enqueue $(\textit{nxt}, v, 1)$.
108+
109+
After the traversal ends, we return $\textit{dist}[n-1][1]$ as the answer.
110+
111+
The time complexity is $O(m \times \log n)$, and the space complexity is $O(n + m)$, where $n$ and $m$ are the number of nodes and edges, respectively.
92112

93113
<!-- tabs:start -->
94114

@@ -358,6 +378,66 @@ function minCostExcludingMax(n: number, edges: number[][]): number {
358378
}
359379
```
360380

381+
#### Rust
382+
383+
```rust
384+
use std::cmp::Reverse;
385+
use std::collections::BinaryHeap;
386+
387+
impl Solution {
388+
pub fn min_cost_excluding_max(n: i32, edges: Vec<Vec<i32>>) -> i64 {
389+
let n = n as usize;
390+
391+
let mut g: Vec<Vec<(usize, i64)>> = vec![Vec::new(); n];
392+
for e in edges {
393+
let u = e[0] as usize;
394+
let v = e[1] as usize;
395+
let w = e[2] as i64;
396+
g[u].push((v, w));
397+
g[v].push((u, w));
398+
}
399+
400+
let inf: i64 = i64::MAX / 4;
401+
let mut dist = vec![[inf; 2]; n];
402+
dist[0][0] = 0;
403+
404+
// (cur_cost, node, used)
405+
let mut pq = BinaryHeap::new();
406+
pq.push(Reverse((0_i64, 0_usize, 0_usize)));
407+
408+
while let Some(Reverse((cur, u, used))) = pq.pop() {
409+
if cur > dist[u][used] {
410+
continue;
411+
}
412+
413+
if u == n - 1 && used == 1 {
414+
return cur;
415+
}
416+
417+
for &(v, w) in &g[u] {
418+
// normal edge
419+
let nxt = cur + w;
420+
if nxt < dist[v][used] {
421+
dist[v][used] = nxt;
422+
pq.push(Reverse((nxt, v, used)));
423+
}
424+
425+
// skip max edge (only once)
426+
if used == 0 {
427+
let nxt = cur;
428+
if nxt < dist[v][1] {
429+
dist[v][1] = nxt;
430+
pq.push(Reverse((nxt, v, 1)));
431+
}
432+
}
433+
}
434+
}
435+
436+
dist[n - 1][1]
437+
}
438+
}
439+
```
440+
361441
<!-- tabs:end -->
362442

363443
<!-- solution:end -->
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use std::cmp::Reverse;
2+
use std::collections::BinaryHeap;
3+
4+
impl Solution {
5+
pub fn min_cost_excluding_max(n: i32, edges: Vec<Vec<i32>>) -> i64 {
6+
let n = n as usize;
7+
8+
let mut g: Vec<Vec<(usize, i64)>> = vec![Vec::new(); n];
9+
for e in edges {
10+
let u = e[0] as usize;
11+
let v = e[1] as usize;
12+
let w = e[2] as i64;
13+
g[u].push((v, w));
14+
g[v].push((u, w));
15+
}
16+
17+
let inf: i64 = i64::MAX / 4;
18+
let mut dist = vec![[inf; 2]; n];
19+
dist[0][0] = 0;
20+
21+
// (cur_cost, node, used)
22+
let mut pq = BinaryHeap::new();
23+
pq.push(Reverse((0_i64, 0_usize, 0_usize)));
24+
25+
while let Some(Reverse((cur, u, used))) = pq.pop() {
26+
if cur > dist[u][used] {
27+
continue;
28+
}
29+
30+
if u == n - 1 && used == 1 {
31+
return cur;
32+
}
33+
34+
for &(v, w) in &g[u] {
35+
// normal edge
36+
let nxt = cur + w;
37+
if nxt < dist[v][used] {
38+
dist[v][used] = nxt;
39+
pq.push(Reverse((nxt, v, used)));
40+
}
41+
42+
// skip max edge (only once)
43+
if used == 0 {
44+
let nxt = cur;
45+
if nxt < dist[v][1] {
46+
dist[v][1] = nxt;
47+
pq.push(Reverse((nxt, v, 1)));
48+
}
49+
}
50+
}
51+
}
52+
53+
dist[n - 1][1]
54+
}
55+
}

0 commit comments

Comments
 (0)