阅读视图

发现新文章,点击刷新页面。

[Python3/Java/C++/Go/TypeScript] 一题一解:Dijkstra 算法(清晰题解)

方法一:Dijkstra 算法

我们可以按照题目描述,构造一个有向图 $g$,其中每条边 $(u, v)$ 有两种走法:

  • 直接走,花费 $w$,对应边 $(u, v)$。
  • 反转走,花费 $2w$,对应边 $(v, u)$。

然后我们可以使用 Dijkstra 算法在图 $G$ 上求解从节点 $0$ 到节点 $n-1$ 的最短路径,即为所求的最小总成本。

具体地,我们定义一个优先队列 $pq$,其中每个元素为一个二元组 $(d, u)$,表示当前到达节点 $u$ 的最小花费为 $d$。我们还定义一个数组 $\textit{dist}$,其中 $\textit{dist}[u]$ 表示从节点 $0$ 到节点 $u$ 的最小花费。初始时,我们将 $\textit{dist}[0] = 0$,其他节点的花费均设为无穷大,并将 $(0, 0)$ 入队。

在每次迭代中,我们从优先队列中取出花费最小的节点 $(d, u)$,如果 $d$ 大于 $\textit{dist}[u]$,则跳过该节点。否则,我们遍历节点 $u$ 的所有邻居节点 $v$,计算通过节点 $u$ 到达节点 $v$ 的新花费 $nd = d + w$,如果 $nd$ 小于 $\textit{dist}[v]$,则更新 $\textit{dist}[v] = nd$ 并将 $(nd, v)$ 入队。

当我们取出节点 $n-1$ 时,此时的 $d$ 即为从节点 $0$ 到节点 $n-1$ 的最小总成本。如果优先队列为空且未取出节点 $n-1$,则说明无法到达节点 $n-1$,返回 -1。

###python

class Solution:
    def minCost(self, n: int, edges: List[List[int]]) -> int:
        g = [[] for _ in range(n)]
        for u, v, w in edges:
            g[u].append((v, w))
            g[v].append((u, w * 2))
        pq = [(0, 0)]
        dist = [inf] * n
        dist[0] = 0
        while pq:
            d, u = heappop(pq)
            if d > dist[u]:
                continue
            if u == n - 1:
                return d
            for v, w in g[u]:
                nd = d + w
                if nd < dist[v]:
                    dist[v] = nd
                    heappush(pq, (nd, v))
        return -1

###java

class Solution {
    public int minCost(int n, int[][] edges) {
        List<int[]>[] g = new ArrayList[n];
        Arrays.setAll(g, k -> new ArrayList<>());
        for (int[] e : edges) {
            int u = e[0], v = e[1], w = e[2];
            g[u].add(new int[] {v, w});
            g[v].add(new int[] {u, w * 2});
        }

        final int inf = Integer.MAX_VALUE / 2;
        int[] dist = new int[n];
        Arrays.fill(dist, inf);
        dist[0] = 0;

        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
        pq.offer(new int[] {0, 0});

        while (!pq.isEmpty()) {
            int[] cur = pq.poll();
            int d = cur[0], u = cur[1];
            if (d > dist[u]) {
                continue;
            }
            if (u == n - 1) {
                return d;
            }
            for (int[] nei : g[u]) {
                int v = nei[0], w = nei[1];
                int nd = d + w;
                if (nd < dist[v]) {
                    dist[v] = nd;
                    pq.offer(new int[] {nd, v});
                }
            }
        }
        return -1;
    }
}

###cpp

class Solution {
public:
    int minCost(int n, vector<vector<int>>& edges) {
        using pii = pair<int, int>;
        vector<vector<pii>> g(n);
        for (auto& e : edges) {
            int u = e[0], v = e[1], w = e[2];
            g[u].push_back({v, w});
            g[v].push_back({u, w * 2});
        }

        const int inf = INT_MAX / 2;
        vector<int> dist(n, inf);
        dist[0] = 0;

        priority_queue<pii, vector<pii>, greater<pii>> pq;
        pq.push({0, 0});

        while (!pq.empty()) {
            auto [d, u] = pq.top();
            pq.pop();
            if (d > dist[u]) {
                continue;
            }
            if (u == n - 1) {
                return d;
            }

            for (auto& [v, w] : g[u]) {
                int nd = d + w;
                if (nd < dist[v]) {
                    dist[v] = nd;
                    pq.push({nd, v});
                }
            }
        }
        return -1;
    }
};

###go

func minCost(n int, edges [][]int) int {
g := make([][][2]int, n)
for _, e := range edges {
u, v, w := e[0], e[1], e[2]
g[u] = append(g[u], [2]int{v, w})
g[v] = append(g[v], [2]int{u, w * 2})
}

inf := math.MaxInt / 2
dist := make([]int, n)
for i := range dist {
dist[i] = inf
}
dist[0] = 0

pq := &hp{}
heap.Init(pq)
heap.Push(pq, pair{0, 0})

for pq.Len() > 0 {
cur := heap.Pop(pq).(pair)
d, u := cur.x, cur.i
if d > dist[u] {
continue
}
if u == n-1 {
return d
}
for _, ne := range g[u] {
v, w := ne[0], ne[1]
if nd := d + w; nd < dist[v] {
dist[v] = nd
heap.Push(pq, pair{nd, v})
}
}
}
return -1
}

type pair struct{ x, i int }
type hp []pair

func (h hp) Len() int           { return len(h) }
func (h hp) Less(i, j int) bool { return h[i].x < h[j].x }
func (h hp) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(x any)        { *h = append(*h, x.(pair)) }
func (h *hp) Pop() (x any) {
a := *h
x = a[len(a)-1]
*h = a[:len(a)-1]
return
}

###ts

function minCost(n: number, edges: number[][]): number {
    const g: number[][][] = Array.from({ length: n }, () => []);
    for (const [u, v, w] of edges) {
        g[u].push([v, w]);
        g[v].push([u, w * 2]);
    }
    const dist: number[] = Array(n).fill(Infinity);
    dist[0] = 0;
    const pq = new PriorityQueue<number[]>((a, b) => a[0] - b[0]);
    pq.enqueue([0, 0]);
    while (!pq.isEmpty()) {
        const [d, u] = pq.dequeue();
        if (d > dist[u]) {
            continue;
        }
        if (u === n - 1) {
            return d;
        }
        for (const [v, w] of g[u]) {
            const nd = d + w;
            if (nd < dist[v]) {
                dist[v] = nd;
                pq.enqueue([nd, v]);
            }
        }
    }
    return -1;
}

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


有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈 😄~

❌