基础
刷题
dijkstra 算法 (堆优化)
图的存储
关于图的存储主要有两种:邻接矩阵和 和 邻接表
邻接矩阵
邻接矩阵的优点:
- 表达方式简单,易于理解
- 检查任意两个顶点间是否存在边的操作非常快
- 适合稠密图,在边数接近顶点数平方的图中,邻接矩阵是一种空间效率较高的表示方法。
缺点:
- 遇到稀疏图,会导致申请过大的二维数组造成空间浪费 且遍历 边 的时候需要遍历整个n * n矩阵,造成时间浪费
邻接表
邻接表的优点:
- 对于稀疏图的存储,只需要存储边,空间利用率高
- 遍历节点链接情况相对容易
缺点:
- 检查任意两个节点间是否存在边,效率相对低,需要 O(V)时间,V表示某节点链接其他节点的数量。
- 实现相对复杂,不易理解
堆排序
container/heap package
package main
import (
"container/heap"
"fmt"
)
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } // 最小堆
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func main() {
h := &IntHeap{2, 1, 5}
heap.Init(h)
heap.Push(h, 3)
fmt.Printf("最小值: %d\n", (*h))
for h.Len() > 0 {
fmt.Printf("%d ", heap.Pop(h))
}
// 输出: 最小值: 1 1 2 3 5
}
- 城市间货物运输 I
加了updated,来判断是否 所有的边都会影响minDist里面的数组,如果没有影响,可以直接跳出,优化程序。但是还是会超时。
具体思路:
Bellman_ford 算法
Bellman_ford算法的核心思想是 对所有边进行松弛n-1次操作(n为节点数量),从而求得目标最短路。
当使用前面的思路,例如prim,dijkstra算法,你无法使用最短的那个路径,因为图的边权值是存在负数的,当你判定这条边是最短的,有可能会存在多个边加在一起会更短,因为有负数权值的边。
因为会存在环路,不能按照节点的考虑,只能按照边来考虑,故 使用 Bellman_ford算法,对所有的边 松弛 n-1次。
这里的 松弛 是指多个边指向一个节点, 当遍历到 c -> b,if (value1 < value) { minDist[B] = value1}, 找到最合适的边的权值(这里求的是最小值)
为什么是n-1次?
首先n是节点的数量,n-1次是理论上需要的最大次数。因为当遍历一个边,出发节点如果没有被计算,就无法计算这个边的,所以最差的情况是,每一次只能遍历一条边,而从1到n,最长需要有n-1个边(不考虑环)
总结
dijkstra算法堆优化算法需要再做一遍