如果我们要求最短路径的时带权图,那么问题就变得复杂起来了,因为我们要找的路线不是像无权图那样简单的找经过边最少的路径。
例如:
我们设置V1为起点,V6为终点
最短路径是V1 -> V4 -> V7 -> V6
而不是V1 -> V4 -> V6
我们可以把无权图最短路径的算法当做是有权图最短路径算法的一个特例,他们的权恰好相等且都为1,那么他们的算法一定有共同之处。
解决这个问题的算法就是Dijkstra算法。
Dijkstra算法像无权最短路径算法一样,按阶段进行。在每个阶段,Dijkstra算法选择一个顶点V,它在所有未知顶点中具有最小的dv,同时算法从s到v的最短路径是已知的。阶段的其余部分由dw值的更新工作组成。
我们拿这个图举例子
同样的可以用一个队列来实现这个算法。
首先我们初始化用于该算法的表,所有的点都标记为未知,dv(路径长度)设置为正无穷大(因为最短路径嘛!)
设开始的结点s是v1,s到s的路径长为0,将其入队,接着标记该点已知。
在出队的同时将他的邻接点v2,v4入队,调整s到v2,v4的路径长度,并标记其为已知。
接着将v2出队,将v5入队,调整s到v5的长度……之后的步骤一次类推,直到所有的顶点都被标记为已知。
我们如何调整开始点s到每一个顶点的路径长度呢?这涉及到了贪心算法。
贪心算法一般地分阶段求解一个问题,在每个阶段它都把当前出现地当作是最好地去处理。
我们在调整其路径长度地时候,将原有值和现在地值进行比较,取最小值(时刻谨记我们的目标(●’◡’●) -> 最短路径)
各阶段图解如下~
伪代码描述:
算法声明:
typedef int Vertex;
struct TableEntry
{
List Header; //Adjacency list
int Known;
DistType Dist; //权重
Vertex Path;
};
#define NotAVertex(-1)
typedef struct TableEntry Table[NumVertex];
表初始化例程
void
InitTable(Vertex Start, Gragh G, Table T)
{
int i;
ReadGragh(G, T); //以某种方式扫描图
for(i = 0; i < NumVertex; i++)
{
T[i].Known = False; //设所有点为未知
T[i].Dist = Infinity; //设到达所有边的路径长度为无穷大
T[i].Path = NotAVertex; //不是一个点
}
T[Start].Dist = 0; //起始点到其本身的距离初始化为0
}
显示实际最短路径的例程
void
PrintfPath(Vertex V, Table T)
{
if(T[V].Path != NotAVertex)
{
PrintfPath(T[V].Path, T); //递归
printf("to");
}
printf("%v", V); //%v is pseudocode
Dijkstra算法
void
Dijkstra(Table T)
{
Vertex V, W;
for(; ; ; )
{
V = smallest unknown distance vertex;
if(V == NotAVertex)
break;
T[V].Known = true;
for each W adjacent to V
if( !T[W].Known)
if(T[V].Dist+ Cvw < T[W].Dist)
{
//Update W
Decrease(T[W].Dist TO T[V].Dist+ Cvw);
T[W].Path = V;
}
}
}