【坚持不能偷懒】
V 定点数 E 边数
【原生DIJ】
从初始点出发 V 次循环
每次对当前点扩展【有效边】 (如果直接对所有点刷 是 V ,而用链表刷有效边是总计为E )
更新已知最短路
再取出【权值最低点】作为新点重复 (寻最小值 V )
故复杂度为 V * V + E
【DIJ 的 Heap 优化】
考虑到每次找【权值最低点】这一步,对其进行堆优化
其具体措施是
写一个堆
然后每次有点扩展【有效边】时,【改变了权值】,则更新堆
这样,每次【更新堆】是一个Log V 的复杂度
点的进入必然会引起更新
每条边的刷新 也都可能引起更新
所以最坏需要 E + V 次更新
故复杂度为 ( E + V )* Log V
—————————————PS———————————————
有人似乎直接用头文件自带的【优先队列】来优化DIJ
我读了其中两则代码,发现他们是用
【优先队列存下标】
【对应数组存当前最小值】
每次新进则PUSH。
BUT,直接更新数组的话,优先队列是不会更新的
我试着写了一个【优先队列存下标,对应数组值变动,然后改掉数组内的值,PUSH新数】的小测试
发现【不能在PUSH后正确更新】
【如果改动之后还能正确更新的话,不就是一个排序的 N Log N 的过程的了么……】
用优先队列直接优化DIJ 很明显是在逗宝宝……
—————————————PPS————————————————
2017.3.16
哈,前几天和大祥子提到这,发现我理解错了,用优先队列也是可以搞的
不过上面那种搞法确实是错的
用优先队列搞
就是每次更新,就在优先队列里直接加入这个新的值
然后优先队列Pop出一个被改过的值,就Pass掉
这样会让优先队列变大,比堆效率差点,需要的空间多些,但还是可以搞的
具体怎么Pass,譬如优先队列里存(点,权)
然后再开个数组记录(点,权)
每个点的权保持最小,如果Pop出的权比数组里的大,说明是无效的,就Pass掉。
【SPFA】
首先这个算法的名字有槽点…… 据说歪果仁不这么叫……
SPFA能处理 无负环的所有问题
SPFA的过程是
用一个队列维护【被更新的点】
然后从队头开始刷刷刷
如果更新了队内的点,不管
如果更新了队外的点,加进来
有些不明所以不明觉厉的博客告诉我们,这个基本跑两回以内就能刷出结果
即复杂度为 K * E
而 K 是一个小的常数……
麻辣个鸡蛋的……
这很明显是在逗我…… 要这样还怎么被各种卡……
同普通DIJ,最坏还是可以刷 V 回 的,然后就炸了
故复杂度为 V * E ( 不被卡可视为 E )
三个分别是
【原生DIJ】
V * V + E (稳定的复杂度)
【DIJ 的 Heap 优化】 ( E + V )* Log V (E为更新次数,通常不会达到)
理想情况 VlogV——针对稠密图
最劣恶化 V * V * Log V——特殊完全图
【SPFA】V * E(V为更新次数,通常不会达到)
理想情况E —— 针对稀疏图
最劣情况V * V * V—— 特殊完全图