跳转至

3807. 修复边以遍历图的最小成本 🔒

题目描述

给定一个下标从 0 到 n - 1 的 n 个节点的 无向图。该图由 m 条边组成,用一个二维整数数组 edges 表示,其中 edges[i] = [ui, vi, wi] 表示节点 ui 和 vi 之间有一条修复成本为 wi 的边。

同时给定一个整数 k。一开始,所有 边都是被损环的。

你可以选择一个非负整数 money并修复所有修复成本 小于或等于 money 的边。其他所有边保持损坏状态,无法使用。

你想要从节点 0 出发,使用最多 k 条边到达节点 n - 1

返回一个整数,表示实现此目标所需的 最小 成本,如果不可能则返回 -1。

 

示例 1:

输入:n = 3, edges = [[0,1,10],[1,2,10],[0,2,100]], k = 1

输出:100

解释:

唯一使用最多 k = 1 条边的合法路径是 0 -> 2,这需要花费 100 来修复边。因此,所需的最低成本是 100。

示例 2:

输入:n = 6, edges = [[0,2,5],[2,3,6],[3,4,7],[4,5,5],[0,1,10],[1,5,12],[0,3,9],[1,2,8],[2,4,11]], k = 2

输出:12

解释:

  • 由于 money = 12,所有修复成本不超过 12 的边都变得可用。
  • 这使得存在路径 0 -> 1 -> 5,使用恰好 2 条边到达节点 5。
  • 如果 money < 12,不存在从节点 0 到节点 5 长度最多为 k = 2 的合法路径。
  • 因此,所需的最少成本是 12。

示例 3:

输入:n = 3, edges = [[0,1,1]], k = 1

输出:-1

解释:

从节点 0 无法使用任何金额到达节点 2。因此,答案是 -1。

 

提示:

  • 2 <= n <= 5 * 104
  • 1 <= edges.length == m <= 105
  • edges[i] = [ui, vi, wi]
  • 0 <= ui, vi < n
  • 1 <= wi <= 109
  • 1 <= k <= n
  • 图中没有自环或重复边。

解法

方法一:二分查找 + BFS

我们注意到,修复边的成本越高,可用的边就越多,越容易满足从节点 \(0\) 出发,使用最多 \(k\) 条边到达节点 \(n - 1\) 的要求。并且,最小的修复成本一定在 \(\textit{edges}\) 中,因此,我们先对 \(\textit{edges}\) 按照修复成本进行排序,然后使用二分查找来寻找满足要求的最小修复成本。

我们二分枚举修复成本的下标,定义左边界 \(l = 0\),右边界 \(r = |\textit{edges}| - 1\)。对于中间位置 \(mid = \lfloor (l + r) / 2 \rfloor\),我们将修复成本小于等于 \(\textit{edges}[mid][2]\) 的边加入图中,然后使用 BFS 判断从节点 \(0\) 出发,是否可以使用最多 \(k\) 条边到达节点 \(n - 1\)。如果可以,则将右边界更新为 \(r = mid\);否则,将左边界更新为 \(l = mid + 1\)。当二分查找结束后,我们需要再进行一次 BFS 判断 \(\textit{edges}[l][2]\) 是否满足要求,如果满足则返回 \(\textit{edges}[l][2]\),否则返回 \(-1\)

时间复杂度 \(O((m + n) \times \log m)\),空间复杂度 \(O(n)\)。其中 \(n\)\(m\) 分别是节点数和边数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution:
    def minCost(self, n: int, edges: List[List[int]], k: int) -> int:
        def check(idx: int) -> bool:
            g = [[] for _ in range(n)]
            for u, v, _ in edges[: idx + 1]:
                g[u].append(v)
                g[v].append(u)
            q = [0]
            dist = 0
            vis = [False] * n
            vis[0] = True
            while q:
                nq = []
                for u in q:
                    if u == n - 1:
                        return dist <= k
                    for v in g[u]:
                        if not vis[v]:
                            vis[v] = True
                            nq.append(v)
                q = nq
                dist += 1
            return False

        m = len(edges)
        edges.sort(key=lambda x: x[2])
        l, r = 0, m - 1
        while l < r:
            mid = (l + r) >> 1
            if check(mid):
                r = mid
            else:
                l = mid + 1
        return edges[l][2] if check(l) else -1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Solution {
    private int n;
    private int[][] edges;
    private int k;

    public int minCost(int n, int[][] edges, int k) {
        this.n = n;
        this.edges = edges;
        this.k = k;
        Arrays.sort(edges, (a, b) -> a[2] - b[2]);
        int l = 0, r = edges.length - 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        return check(l) ? edges[l][2] : -1;
    }

    private boolean check(int idx) {
        List<Integer>[] g = new List[n];
        Arrays.setAll(g, i -> new ArrayList<>());
        for (int i = 0; i <= idx; ++i) {
            int u = edges[i][0], v = edges[i][1];
            g[u].add(v);
            g[v].add(u);
        }
        List<Integer> q = new ArrayList<>();
        q.add(0);
        int dist = 0;
        boolean[] vis = new boolean[n];
        vis[0] = true;
        while (!q.isEmpty()) {
            List<Integer> nq = new ArrayList<>();
            for (int u : q) {
                if (u == n - 1) {
                    return dist <= k;
                }
                for (int v : g[u]) {
                    if (!vis[v]) {
                        vis[v] = true;
                        nq.add(v);
                    }
                }
            }
            q = nq;
            ++dist;
        }
        return false;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Solution {
public:
    int minCost(int n, vector<vector<int>>& edges, int k) {
        sort(edges.begin(), edges.end(),
            [](const vector<int>& a, const vector<int>& b) {
                return a[2] < b[2];
            });

        auto check = [&](int idx) -> bool {
            vector<vector<int>> g(n);
            for (int i = 0; i <= idx; ++i) {
                int u = edges[i][0], v = edges[i][1];
                g[u].push_back(v);
                g[v].push_back(u);
            }

            vector<int> q;
            q.push_back(0);
            vector<char> vis(n, 0);
            vis[0] = 1;

            int dist = 0;
            while (!q.empty()) {
                vector<int> nq;
                for (int u : q) {
                    if (u == n - 1) {
                        return dist <= k;
                    }
                    for (int v : g[u]) {
                        if (!vis[v]) {
                            vis[v] = 1;
                            nq.push_back(v);
                        }
                    }
                }
                q.swap(nq);
                ++dist;
            }
            return false;
        };

        int m = edges.size();
        int l = 0, r = m - 1;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (check(mid)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        return check(l) ? edges[l][2] : -1;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
func minCost(n int, edges [][]int, k int) int {
    sort.Slice(edges, func(i, j int) bool {
        return edges[i][2] < edges[j][2]
    })

    check := func(idx int) bool {
        g := make([][]int, n)
        for i := 0; i <= idx; i++ {
            u, v := edges[i][0], edges[i][1]
            g[u] = append(g[u], v)
            g[v] = append(g[v], u)
        }

        q := make([]int, 0, n)
        q = append(q, 0)
        vis := make([]bool, n)
        vis[0] = true

        dist := 0
        for len(q) > 0 {
            nq := make([]int, 0)
            for _, u := range q {
                if u == n-1 {
                    return dist <= k
                }
                for _, v := range g[u] {
                    if !vis[v] {
                        vis[v] = true
                        nq = append(nq, v)
                    }
                }
            }
            q = nq
            dist++
        }
        return false
    }

    m := len(edges)
    l, r := 0, m-1
    for l < r {
        mid := (l + r) >> 1
        if check(mid) {
            r = mid
        } else {
            l = mid + 1
        }
    }
    if check(l) {
        return edges[l][2]
    }
    return -1
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function minCost(n: number, edges: number[][], k: number): number {
    edges.sort((a, b) => a[2] - b[2]);

    const check = (idx: number): boolean => {
        const g: number[][] = Array.from({ length: n }, () => []);
        for (let i = 0; i <= idx; i++) {
            const [u, v] = edges[i];
            g[u].push(v);
            g[v].push(u);
        }

        let q: number[] = [0];
        const vis: boolean[] = Array(n).fill(false);
        vis[0] = true;

        let dist = 0;
        while (q.length > 0) {
            const nq: number[] = [];
            for (const u of q) {
                if (u === n - 1) {
                    return dist <= k;
                }
                for (const v of g[u]) {
                    if (!vis[v]) {
                        vis[v] = true;
                        nq.push(v);
                    }
                }
            }
            q = nq;
            dist++;
        }
        return false;
    };

    let [l, r] = [0, edges.length - 1];
    while (l < r) {
        const mid = (l + r) >> 1;
        if (check(mid)) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }
    return check(l) ? edges[l][2] : -1;
}

评论