前言
有一题求最短路 和最长路的题,由于基础不够扎实,天真地以为改一下松弛操作、重载一下优先队列即可。事实上,经典Dijkstra并不能求最长路。
经典Dijkstra不能求最长路原理
在经典Dijkstra中,根据贪心思想,我们每次使用一个距离源点最短的点A来松弛其他点,并且保证了这个操作每个点只会进行一次,也即每个点有且仅有一次作为点A(除了距离最远的点,因为最后一点被松弛完整个算法就结束了)。
众所周知,迪杰斯特拉的使用条件是图中不存在负边。这是因为在不存在负边权的图中,最短路有子结构,子路径最短能保证总路径最短。根据这一性质,也有了一个结论,上面提到的用来松弛其他点的那个点A,距离源点的距离已经是最短的(这也是Dijsktra每个点只用来松弛一次的前提)。然而,以下两种情况不存在子结构:
- 存在负边权,例如
- 求最长路,例如
在不存在子结构的图中,一个点用来松弛其他点的点,未必已经是最优解。所以,我们可以使用允许多次松弛的算法(SPFA、经典Dijsktra改成允许一个点松弛其他点多次,事实上就应该称为SPFA了)来求最长路。
总结
- 正权边图中求最长路可使用SPFA
- 经典Dijsktra可在全负权边图中跑最长路、全正权边图中跑最短路
- Dijsktra+堆优化的时间复杂度为O(ElogV)、SPFA(Bellman Ford)+堆优化的时间复杂度是O(VE)。