最短路径
1.概念
- 单源最短路径
单源最短路径实际是计算源点到其他各个顶点的最短路径的长度,常见算法有dijkstra算法
- 全局最短路径
全局最短路径实际是计算每个源点到其他各个顶点的最短路径的长度,我们可以调用dijkstra算法N次(这样没有Floyd算法快),常见解决全局最短路径的方法是Floyd-Warshall算法,但是Floyd-Warshall算法不能解决负边问题。为了解决负边问题,我们使用Bellman-Ford算法,或者SPFA(Shortest Path Faster Algorithm),SPFA是Bellman-Ford队列优化算法的别称
- 注意点
很多人看到dijkstra、Floyd-Warshall、SPFA、Bellman-Ford会比较头疼。那就仅先掌握2种算法,优先掌握dijkstra、Floyd-Warshall算法,毕竟,这两个收录在教科书内,理论上来说会比较重要。而在PAT解题过程中,也是优先使用Dijstra算法(PAT往往不会因为短路问题超时)。
2.Dijkstra
Dijkstra算法解决单源带权最短路径十分有效。步骤如下:
- 令S = {源点s + 已经确定了最短路径的顶点vi}
- 对任一未收录的顶点v,定义dist[v]为s到v的最短路径长度,但该路径仅经过S中的顶点,即路径{ S -> (vi 包含于 S) -> v}的最小长度
- 路径是按照递增(非递减的顺序生成的,则
void Dijstra( Vertex s ) {
while(1) {
V = 未收录顶点中dist最小者
if( 这样的V不存在 ) break;
collected[V] = true;
for( V 的每个邻接点 W )
if(collected[W] == false && dist[V] + E<v,w> < dist[W]) {
dist[W] = dist[V] + E<v,w>;
path[W] = V;
}
}
}
3.Floyd-Warshall
我们为了解决多源最短路径问题,我们可以采用调用N遍Dijsktra算法,这样复杂度T = O(|V|^3+|E|+|V|),也可以采用Floyd-Warshall,复杂度为T = O(|V|^3),在稀疏图,我们可以使用Dijstra算法进行解决,而在稠密图,Floyd会彰显优势。Floyd-Warshall的流程比较简单。流程如下:
void Floyd(){
for(k = 0; k < N; k++)
for(i = 0; i < N; i++)
for(j = 0; j < N; j++)
if(D[i][k] + D[k][j] < D[i][j]) {
D[i][j] = D[i][k] + D[k][j];
path[i][j] = k;
}
}
4.练习
关于PAT,有这几题是最短路径问题的练习。参考:https://www.liuchuo.net/archives/2502
- 1003.Emergency(Dijkstra算法)
- 1018.Public Bike Management(Dijkstra算法+DFS)
- 1030.Travel Plan (Dijkstra + DFS,输出路径+边权)
- 1087.All Roads Lead to Rome (Dijstra算法+DFS)
- 1111.Online Map(Dijkstra算法+DFS)