最短路径问题
典型用途
交通网络的问题——从甲地到乙地之间是否有公路连通?在有多条通路的情况下,哪一条路最短? 交通网络用有向图来表示: 顶点——表示地点, 弧——表示两个地点有路连通, 弧上的权值——表示两地点之间的距离、交通费或图中所花费的时间等。
如何能够使一个地点到另一个地点的运输时间最短或运费最省?这就是一个求两个地点间的最短路径的问题。
问题抽象
在有向网中A点(源点)到达B点(终点)的多条路径中,寻找一条各边权值之和最小的路径,即最短路径。
最短路径与最小生成树不同,路径上不一定包含n个顶点,也不一定包含n-1条边。
引出问题
第一类问题:两点间最短路径
用Dijkstra(迪杰斯特拉)算法。
第二类问题:某源点到其他各点最短路径
用Floyd(弗洛伊德)算法。
Dijistra算法
(1)初始化:先找出从源点v0到各终点vk的直达路径(v0, vk),即通过一条弧到达的路径。 (2)选择:从这些路径中找出一条长度最短的路径(v0, u)。 (3)更新:然后对其余各条路径进行适当调整: 若在图中存在弧(u, vk),且(v0, u) + (u, vk) < (v0, vk),则以路径(v0, u, vk)代替(v0, vk)。 在调整后的各条路径中,再找长度最短的路径,以此类推。
void ShortestPath_DIJ(AMGraph G, int v0)
{
n=G.vexnum;
for(v= O;v<n; ++v)
{
S[v]=false;
D[v]=G.arcs[v0][v];
if(D[v]<Maxlnt) Path[v]=vO;
else Path[v]=-1;
}
S[v0] = true;
D[v0]=0;
for(i=1;i<n;++i)
{
min=MaxInt;
for(w= O;w<n;++w)
if(!S[w]&&D[w]<min)
{v=w;min=D[w];}
S[v]=true;
for(w=0;w<n;++w)
if(!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
{
D[w]=D[v]+G.arcs[v][w];
Path[w]=v;
}
}
}
迪杰斯特拉(Dijkstra)算法描述
按路径长度递增次序产生最短路径 1.把V分成两组: (1)S:已求出最短路径的顶点的集合。 (2)T=V-S:尚未确定最短路径的顶点集合。 2.将T中顶点按最短路径递增的次序加入到S中,保证: (1)从源点v0到S中各顶点的最短路径长度都不大于从v0到T中任何顶点的最短路径长度。 (2)每个顶点对应一个距离值: S中顶点:从v0到此顶点的最短路径长度。 T中顶点:从v0到此顶点的只包括S中顶点作中间顶点的最短路径长度。
算法步骤
初始时令S={v0},T={其余顶点}。
实例
弗洛伊德(Floyd)算法
初始时设置一个n阶方阵,令其对角线元素为0,若存在弧<vi, vj>,则对应元素为权值;否则为∞。 逐步试着在原直接路径中增加中间顶点,若加入中间顶点后路径变短,则修改之;否则,维持原值。所有顶点试探完毕,算法结束。
void ShortestPath_Floyd(AMGraph G)
{
for (i=O; i < G.vexnum; ++i)
for(j=O;j <G.vexnum;++j)
{
D[i][j] =G.arcs [i][j];
if(D[i][j]<Maxint) Path[i][j]=i;
else Path[i][j]=-1;
}
for (k=O; k < G.vexnum; ++k)
for (i=O; i <G.vexnum;++i)
for(j=O;j <G.vexnum;++j)
if(D[i][k]+D[k][j] <D[i][j])
{
D[i][j]=D[i][k]+D[k][j];
Path[i][j]=Path[k][j];
}
}
算法思想
- 逐个顶点试探;
- 从vi到vj的所有可能存在的路径中;
- 选出一条长度最短的路径。
实例
|