算法 - 图论10(Swift版本)

4 阅读2分钟

Bellman_ford 不同场景的应用。

题目1: Bellman_ford 队列优化算法

讲解

对于bellman_ford做了队列优化,也就是这个判断 minDist[from] != Int.max 用队列替换了。 bellman_ford基础版本

func bellmanFordQueue(n: Int, e: Int, grid: [[Int]]) {
    var minDist = Array(repeating: Int.max, count: n + 1)
    // 此题中元素是否有被加入queue中可以不用统计, 重复加入正权回路 最后没问题。 负权回路本题限制不会出现。
    var inqueue = Array(repeating: false, count: n + 1)
    var stack = [Int]()
    // 邻接表 from: [(to: val)]
    var map = [Int: [(Int, Int)]]()
    for line in grid {
        var list = map[line[0], default: []]
        list.append((line[1], line[2]))
        map[line[0]] = list
    }
    print("\(map)")
    minDist[1] = 0
    inqueue[1] = true
    stack = [1]
    while !stack.isEmpty {
        let from = stack.removeLast()
        inqueue[from] = false
        for line in map[from] ?? [] {
            if minDist[line.0] > minDist[from] + line.1 {
                minDist[line.0] = minDist[from] + line.1
                if inqueue[line.0] == false {
                    stack.append(line.0)
                    inqueue[line.0] = true
                }
            }
        }
    }
    if minDist[n] == Int.max {
        print("unconnected")
    } else {
        print("\(minDist[n])")
    }
}

bellmanFordQueue(n: 6, e: 5, grid: [[5, 6, 1], [4, 5, 1], [3, 4, 1], [2, 3, 1], [1, 2, 1]]) // 5
bellmanFordQueue(n: 6, e: 7, grid: [[5, 6, -2], [1, 2, 1], [5, 3, 1], [2, 5, 2], [2, 4, -3], [4, 6, 4], [1, 3, 5]]) // 1
bellmanFordQueue(n: 4, e: 2, grid: [[1, 2, -1], [3, 4, -1]]) // unconnected

题目2: bellman_ford之判断负权回路

讲解

负权回路终于出现了。

负权回路的处理,基于以上两种都可以做判断。

  1. bellmanFord 算法,如果没有负权回路最多松弛n-1次就不会变化了,所以可以统计如果松弛第n次 还有变化,那么就是有负权回路了。
  2. bellmanFord 队列优化算法, 每个点最多被连接n-1次, 如果发现某个点被入队n次, 那么就是有负权回路了。

题目3:bellman_ford之单源有限最短路

讲解

有限的路径。 其中的重点是 每次要使用上轮计算的结果来做松弛, 而不是在本次的基础上。
这样的话因为有负权回路的存在,每多执行一次, 结果就会有变化。
而前面不用考虑的原因是:

  1. 判断负权回路 : 都是判断最多执行n-1次就不应该变化了。 中间多执行几次,相当于提前完成了n-1次,那么到实际遍历了n-1次时,如果有负权回路,依旧会变化,如果没负权回路,早就不变化了。 对结果没影响。
  2. bellman_ford基础版本: 没有负权回路 多执行几次并不会改变结果。
func bellmanFordLimitK(n: Int, e: Int, grid: [[Int]]) {
    var minDist = Array(repeating: Int.max, count: n + 1)
    let src = grid[grid.count - 1][0]
    let dst = grid[grid.count - 1][1]
    let k = grid[grid.count - 1][2]
    let grid = grid[0..<(grid.count - 1)]
    minDist[src] = 0
    print("\(grid) - \(src) \(dst) \(k)")
    for _ in 0...k {
        let minDistCopy = minDist
        minDist[0] = 2
        for line in grid {
            let from = line[0]
            let to = line[1]
            let val = line[2]
            if minDistCopy[from] != Int.max, minDist[to] > minDistCopy[from] + val {
                minDist[to] = minDistCopy[from] + val
            }
        }
    }
    if minDist[dst] == Int.max {
        print("unconnected")
    } else {
        print("\(minDist[dst])")
    }
}

bellmanFordLimitK(n: 6, e: 7, grid: [[1, 2, 1], [2, 4, -3], [2, 5, 2], [1, 3, 5], [3, 5, 1], [4, 6, 4], [5, 6, -2], [2, 6, 1]]) // 0
bellmanFordLimitK(n: 4, e: 4, grid: [[3, 1, -1], [3, 4, 1], [2, 3, 1], [1, 2, -1], [1, 4, 3]]) // 1