Golang算法模板-最短路径模板Dijkstra/Bellman-Ford

170 阅读3分钟

Dijkstra

用一个数组存储一个确定的点到其他各个点的初始距离,并把这个点标记,然后在剩下的n-1个点中找到距离这个给定的点距离最短的点,然后把它标记后,用它当作中转点来松弛给定点到其他点的距离。一共找n-1次就可以了,因为一开始就把给定点标记了。

只适用于解决单源最短路径问题 不能解决负边权因为当扩展到一个负边时,已经更新过的两点之间的距离可能还会被修改掉,这就违背了这个算法已经更新的边为最小值的思想了。 适用于解决稠密图

洛谷P1339 [USACO09OCT] Heat Wave G

https://www.luogu.com.cn/problem/P1339

题目描述
有一个 𝑛*n* 个点 𝑚*m* 条边的无向图,请求出从 𝑠*s* 到 𝑡*t* 的最短路长度。
输入格式
第一行四个正整数 𝑛,𝑚,𝑠,𝑡*n*,*m*,*s*,*t*。 接下来 𝑚*m* 行,每行三个正整数 𝑢,𝑣,𝑤*u*,*v*,*w*,表示一条连接 𝑢,𝑣*u*,*v*,长为 𝑤*w* 的边。
输出格式
输出一行一个整数,表示答案。
package main
​
import (
    "fmt"
    "math"
)
​
var edge [2505][2505]int
var dis [2505]int
var book [2505]int
var n, m, s, t int
var inf = math.MaxInt/2 - 1
​
func dijkstra() {
    for i := 1; i <= n; i++ {
        dis[i] = edge[s][i]
    }
    //fmt.Println(dis[:20])
    book[s] = 1
    for i := 1; i <= n-1; i++ { //在循环开始前对11进行了确定,所以只需要进行n-1次循环就可以
        var minn int = inf
        var nextPos int = -1
        for j := 1; j <= n; j++ {
            if book[j] == 0 && dis[j] < minn {
                nextPos = j
                minn = dis[j]
            }
        }
        if nextPos == -1 {
            break
        }
        book[nextPos] = 1
        for j := 1; j <= n; j++ {
            if book[j] == 0 && dis[nextPos]+edge[nextPos][j] < dis[j] {
                dis[j] = dis[nextPos] + edge[nextPos][j]
            }
        }
    }
}
​
func main() {
    fmt.Scan(&n, &m, &s, &t)
    for i := 1; i <= n; i++ {
        for j := 1; j <= n; j++ {
            if i == j {
                edge[i][j] = 0
            } else {
                edge[i][j] = inf
            }
        }
    }
    for i := 1; i <= m; i++ {
        var u, v, w int
        fmt.Scan(&u, &v, &w)
        if w < edge[u][v] {
            edge[u][v] = w
            edge[v][u] = w
        }
    }
    dijkstra()
    fmt.Printf("%d\n", dis[t])
}

Bellman-Ford

遍历m条边,看是否能让从给定点直接到v点缩短为从给定点到u点再到v点。 因为任意两点之间的最短路径最多包含n-1条边,所以把这些边遍历n-1次就好。

适合解决单源最短路径

因为遍历的是m条边,和边密切相关,所以边数越小,计算越快,适合稀疏图 可以解决负边权,当第n次还能松弛时,说明存在负权回路

package main
​
import (
    "fmt"
    "math"
)
​
type Edge struct {
    u, v, w int
}
​
var edge [6205]Edge
var dis [2505]int
var n, m, s, t int
var inf = math.MaxInt/2 - 1func main() {
    fmt.Scan(&n, &m, &s, &t)
    for i := 1; i <= m; i++ {
        fmt.Scan(&edge[i].u, &edge[i].v, &edge[i].w)
​
    }
    for i := 1; i <= n; i++ {
        dis[i] = inf
    }
    dis[s] = 0                  //以s为起点
    for k := 1; k <= n-1; k++ { //把这些边遍历n-1次
        var check = 0
        for i := 1; i <= m; i++ {
            if dis[edge[i].v] > dis[edge[i].u]+edge[i].w {
                dis[edge[i].v] = dis[edge[i].u] + edge[i].w
                check = 1
            }
            if dis[edge[i].u] > dis[edge[i].v]+edge[i].w {
                dis[edge[i].u] = dis[edge[i].v] + edge[i].w
                check = 1
            }
        }
        if check == 0 {
            break
        }
    }
​
    /*
        判断是否存在负权回路
        var flag = 0
        for i:=1; i<=m; i++{
            if dis[edge[i].v] > dis[edge[i].u]+edge[i].w || dis[edge[i].u] > dis[edge[i].v]+edge[i].w{
                flag = 1
                break
            }
        }
        if flag == 1{
            //存在负权回路
        }
    */
​
    fmt.Printf("%d\n", dis[t])
}

SPFA+邻接表存图

https://blog.csdn.net/weixin_42172261/article/details/104174283