单源点最短路径
2011-12-15 12:27
190 查看
单源点最短路径
对于给定的有向图G=(V,E)及单个源点Vs,求Vs到G的其余各顶点的最短路径。
针对单源点的最短路径问题,Dijkstra提出了一种按路径长度递增次序产生最短路径的算法,即迪杰斯特拉(Dijkstra)算法。
基本思想:从图的给定源点到其它各个顶点之间客观上应存在一条最短路径,在这组最短路径中,按其长度的递增次序,依次求出到不同顶点的最短路径和路径长度。即按长度递增的次序生成各顶点的最短路径,即先求出长度最小的一条最短路径,然后求出长度第二小的最短路径,依此类推,直到求出长度最长的最短路径。
算法思想说明
设给定源点为Vs,S为已求得最短路径的终点集,开始时令S={Vs} 。当求得第一条最短路径(Vs ,Vi)后,S为{Vs,Vi} 。根据以下结论可求下一条最短路径。
设下一条最短路径终点为Vj ,则Vj只有:
◆ 源点到终点有直接的弧<Vs,Vj>;
◆ 从Vs 出发到Vj 的这条最短路径所经过的所有中间顶点必定在S中。即只有这条最短路径的最后一条弧才是从S内某个顶点连接到S外的顶点Vj 。
若定义一个数组dist
,其每个dist[i]分量保存从Vs 出发中间只经过集合S中的顶点而到达Vi的所有路径中长度最小的路径长度值,则下一条最短路径的终点Vj必定是不在S中且值最小的顶点,即:
dist[i]=Min{ dist[k]| Vk∈V-S }
利用上述公式就可以依次找出下一条最短路径。
算法步骤
① 令S={Vs} ,用带权的邻接矩阵表示有向图,对图中每个顶点Vi按以下原则置初值:
② 选择一个顶点Vj ,使得:
dist[j]=Min{ dist[k]| Vk∈V-S }
Vj就是求得的下一条最短路径终点,将Vj 并入到S中,即S=S∪{Vj} 。
③ 对V-S中的每个顶点Vk ,修改dist[k],方法是:
若dist[j]+Wjk<dist[k],则修改为:
dist[k]=dist[j]+Wjk ("Vk∈V-S )
④ 重复②,③,直到S=V为止。
算法实现
用带权的邻接矩阵表示有向图, 对Prim算法略加改动就成了Dijkstra算法,将Prim算法中求每个顶点Vk的lowcost值用dist[k]代替即可。
◆ 设数组pre
保存从Vs到其它顶点的最短路径。若pre[i]=k,表示从Vs 到Vi的最短路径中,Vi的前一个顶点是Vk,即最短路径序列是(Vs , …, Vk , Vi) 。
◆ 设数组final
,标识一个顶点是否已加入S中。
算法实现的关键
待求点的最短路径长度本身就是待求的,又如何找出其中的最短呢?
BOOLEAN final[MAX_VEX] ;
int pre[MAX_VEX] , dist[MAX_VEX] ;
void Dijkstra_path (AdjGraph *G, int v)
/* 从图G中的顶点v出发到其余各顶点的最短路径 */
{
int j, k, m, min ;
for ( j=0; j<G->vexnum; j++)
{
pre[j]=v ;
final[j]=FALSE ;
dist[j]=G->adj[v][j] ;
} /* 各数组的初始化 */
dist[v]=0 ;
final[v]=TRUE ; /* 设置S={v} */
for ( j=0; j<G->vexnum-1; j++) /* 其余n-1个顶点 */
{
m=0 ;
while (final[m]) m++; /* 找不在S中的顶点vk */
min=INFINITY ;
for ( k=0; k<G->vexnum; k++)
{
if (!final[k]&&dist[m]<min)
{
min=dist[k] ;
m=k ;
}
} /* 求出当前最小的dist[k]值 */
final[m]=TRUE ; /* 将第k个顶点并入S中 */
for ( j=0; j<G->vexnum; j++)
{
if (!final[j]&&(dist[m]+G->adj[m][j]<dist[j]))
{
dist[j]=dist[m]+G->adj[m][j] ;
pre[j]=m ;
}
} /* 修改dist和pre数组的值 */
} /* 找到最短路径 */
}
算法分析
Dijkstra算法的主要执行是:
◆ 数组变量的初始化:时间复杂度是O(n) ;
◆ 求最短路径的二重循环:时间复杂度是O(n2) ;
因此,整个算法的时间复杂度是O(n2) 。
对图7-25的带权有向图,用Dijkstra算法求从顶点0到其余各顶点的最短路径,数组dist和pre的各分量的变化如表7-3所示。
求最短路径时数组dist和pre的各分量的变化情况
每一对顶点间的最短路径
每次以一个不同的顶点为源点重复Dijkstra算法便可求得每一对顶点间的最短路径,时间复杂度是O(n3) 。
弗罗伊德(Floyd)提出了另一个算法,其时间复杂度仍是O(n3) , 但算法形式更为简明,步骤更为简单,数据结构仍然是基于图的邻接矩阵。
算法思想
设顶点集S(初值为空),用数组A的每个元素A[i][j]保存从Vi只经过S中的顶点到达Vj的最短路径长度,其思想是:
① 初始时令S={ } , A[i][j]的赋初值方式是:
② 将图中一个顶点Vk 加入到S中,修改A[i][j]的值,修改方法是:
A[i][j]=Min{A[i][j] , (A[i][k]+A[k][j]) }
原因: 从Vj只经过S中的顶点(Vk)到达Vj的路径长度可能比原来不经过Vk的路径更短。
③ 重复②,直到G的所有顶点都加入到S中为止。
2 算法实现
◆ 定义二维数组Path
(n为图的顶点数) ,元素Path[i][j]保存从Vi到Vj的最短路径所经过的顶点。
◆ 若Path[i][j]=k:从Vi到Vj 经过Vk ,最短路径序列是(Vi , …, Vk , …, Vj) ,则路径子序列:(Vi , …, Vk)和(Vk , …, Vj)一定是从Vi到Vk和从Vk到Vj 的最短路径。从而可以根据Path[i][k]和Path[k][j]的值再找到该路径上所经过的其它顶点,…依此类推。
◆ 初始化为Path[i][j]=-1,表示从Vi到Vj 不经过任何(S中的中间)顶点。当某个顶点Vk加入到S中后使A[i][j]变小时,令Path[i][j]=k。
表7-4给出了利用Floyd算法求图7-26的带权有向图的任意一对顶点间最短路径的过程。
根据上述过程中Path[i][j]数组,得出:
V0到V1 :最短路径是{ 0, 1 } ,路径长度是2 ;
V0到V2 :最短路径是{ 0, 1, 2 } ,路径长度是6 ;
V1到V0 :最短路径是{ 1, 2, 0 } ,路径长度是9 ;
V1到V2 :最短路径是{ 1, 2 } ,路径长度是4 ;
V2到V0 :最短路径是{ 2, 0 } ,路径长度是5 ;
V2到V1 :最短路径是{ 2, 0, 1 } ,路径长度是7 ;
算法实现
int A[MAX_VEX][MAX_VEX] ;
int Path[MAX_VEX][MAX_VEX] ;
void Floyd_path (AdjGraph *G)
{
int j, k, m ;
for ( j=0; j<G->vexnum; j++)
for ( k=0; k<G->vexnum; k++)
{
A[j][k]=G->adj[j][k] ;
Path[j][k]=-1 ;
}
/* 各数组的初始化 */
for ( m=0; m<G->vexnum; m++)
for ( j=0; j<G->vexnum; j++)
for ( k=0; k<G->vexnum; k++)
if ((A[j][m]+A[m][k])<A[j][k])
{
A[j][k]=A[j][m]+A[m][k] ;
Path[j][k]=k ;
} /* 修改数组A和Path的元素值 */
for ( j=0; j<G->vexnum; j++)
for ( k=0; k<G->vexnum; k++)
if (j!=k)
{
printf(“%d到%d的最短路径为:\n”, j, k) ;
printf(“%d ”,j) ; prn_pass(j, k) ;
printf(“%d ”, k) ;
printf(“最短路径长度为: %d\n”,A[j][k]) ;
}
}/* end of Floyd */
void prn_pass(int j , int k)
{
if (Path[j][k]!=-1)
{
prn_pass(j, Path[j][k]) ;
printf(“, %d” , Path[j][k]) ;
prn_pass(Path[j][k], k) ;
}
}
对于给定的有向图G=(V,E)及单个源点Vs,求Vs到G的其余各顶点的最短路径。
针对单源点的最短路径问题,Dijkstra提出了一种按路径长度递增次序产生最短路径的算法,即迪杰斯特拉(Dijkstra)算法。
基本思想:从图的给定源点到其它各个顶点之间客观上应存在一条最短路径,在这组最短路径中,按其长度的递增次序,依次求出到不同顶点的最短路径和路径长度。即按长度递增的次序生成各顶点的最短路径,即先求出长度最小的一条最短路径,然后求出长度第二小的最短路径,依此类推,直到求出长度最长的最短路径。
算法思想说明
设给定源点为Vs,S为已求得最短路径的终点集,开始时令S={Vs} 。当求得第一条最短路径(Vs ,Vi)后,S为{Vs,Vi} 。根据以下结论可求下一条最短路径。
设下一条最短路径终点为Vj ,则Vj只有:
◆ 源点到终点有直接的弧<Vs,Vj>;
◆ 从Vs 出发到Vj 的这条最短路径所经过的所有中间顶点必定在S中。即只有这条最短路径的最后一条弧才是从S内某个顶点连接到S外的顶点Vj 。
若定义一个数组dist
,其每个dist[i]分量保存从Vs 出发中间只经过集合S中的顶点而到达Vi的所有路径中长度最小的路径长度值,则下一条最短路径的终点Vj必定是不在S中且值最小的顶点,即:
dist[i]=Min{ dist[k]| Vk∈V-S }
利用上述公式就可以依次找出下一条最短路径。
算法步骤
① 令S={Vs} ,用带权的邻接矩阵表示有向图,对图中每个顶点Vi按以下原则置初值:
② 选择一个顶点Vj ,使得:
dist[j]=Min{ dist[k]| Vk∈V-S }
Vj就是求得的下一条最短路径终点,将Vj 并入到S中,即S=S∪{Vj} 。
③ 对V-S中的每个顶点Vk ,修改dist[k],方法是:
若dist[j]+Wjk<dist[k],则修改为:
dist[k]=dist[j]+Wjk ("Vk∈V-S )
④ 重复②,③,直到S=V为止。
算法实现
用带权的邻接矩阵表示有向图, 对Prim算法略加改动就成了Dijkstra算法,将Prim算法中求每个顶点Vk的lowcost值用dist[k]代替即可。
◆ 设数组pre
保存从Vs到其它顶点的最短路径。若pre[i]=k,表示从Vs 到Vi的最短路径中,Vi的前一个顶点是Vk,即最短路径序列是(Vs , …, Vk , Vi) 。
◆ 设数组final
,标识一个顶点是否已加入S中。
算法实现的关键
待求点的最短路径长度本身就是待求的,又如何找出其中的最短呢?
BOOLEAN final[MAX_VEX] ;
int pre[MAX_VEX] , dist[MAX_VEX] ;
void Dijkstra_path (AdjGraph *G, int v)
/* 从图G中的顶点v出发到其余各顶点的最短路径 */
{
int j, k, m, min ;
for ( j=0; j<G->vexnum; j++)
{
pre[j]=v ;
final[j]=FALSE ;
dist[j]=G->adj[v][j] ;
} /* 各数组的初始化 */
dist[v]=0 ;
final[v]=TRUE ; /* 设置S={v} */
for ( j=0; j<G->vexnum-1; j++) /* 其余n-1个顶点 */
{
m=0 ;
while (final[m]) m++; /* 找不在S中的顶点vk */
min=INFINITY ;
for ( k=0; k<G->vexnum; k++)
{
if (!final[k]&&dist[m]<min)
{
min=dist[k] ;
m=k ;
}
} /* 求出当前最小的dist[k]值 */
final[m]=TRUE ; /* 将第k个顶点并入S中 */
for ( j=0; j<G->vexnum; j++)
{
if (!final[j]&&(dist[m]+G->adj[m][j]<dist[j]))
{
dist[j]=dist[m]+G->adj[m][j] ;
pre[j]=m ;
}
} /* 修改dist和pre数组的值 */
} /* 找到最短路径 */
}
算法分析
Dijkstra算法的主要执行是:
◆ 数组变量的初始化:时间复杂度是O(n) ;
◆ 求最短路径的二重循环:时间复杂度是O(n2) ;
因此,整个算法的时间复杂度是O(n2) 。
对图7-25的带权有向图,用Dijkstra算法求从顶点0到其余各顶点的最短路径,数组dist和pre的各分量的变化如表7-3所示。
求最短路径时数组dist和pre的各分量的变化情况
顶点 步骤 | 1 | 2 | 3 | 4 | 5 | S | |
初态 | Dist pre | 20 0 | 60 0 | ∞ 0 | 10 0 | 65 0 | {0} |
1 | Dist pre | 20 0 | 60 0 | ∞ 0 | 10 0 | 30 4 | {0, 4} |
2 | Dist pre | 20 0 | 50 1 | 90 1 | 10 0 | 30 4 | {0, 4, 1} |
3 | Dist pre | 20 0 | 45 5 | 90 1 | 10 0 | 30 4 | {0, 4, 1, 5} |
4 | Dist pre | 20 0 | 45 5 | 85 2 | 10 0 | 30 4 | {0, 4, 1, 5, 2} |
5 | Dist pre | 20 0 | 45 5 | 85 2 | 10 0 | 30 4 | {0, 4, 1, 5, 2, 3} |
每次以一个不同的顶点为源点重复Dijkstra算法便可求得每一对顶点间的最短路径,时间复杂度是O(n3) 。
弗罗伊德(Floyd)提出了另一个算法,其时间复杂度仍是O(n3) , 但算法形式更为简明,步骤更为简单,数据结构仍然是基于图的邻接矩阵。
算法思想
设顶点集S(初值为空),用数组A的每个元素A[i][j]保存从Vi只经过S中的顶点到达Vj的最短路径长度,其思想是:
① 初始时令S={ } , A[i][j]的赋初值方式是:
② 将图中一个顶点Vk 加入到S中,修改A[i][j]的值,修改方法是:
A[i][j]=Min{A[i][j] , (A[i][k]+A[k][j]) }
原因: 从Vj只经过S中的顶点(Vk)到达Vj的路径长度可能比原来不经过Vk的路径更短。
③ 重复②,直到G的所有顶点都加入到S中为止。
2 算法实现
◆ 定义二维数组Path
(n为图的顶点数) ,元素Path[i][j]保存从Vi到Vj的最短路径所经过的顶点。
◆ 若Path[i][j]=k:从Vi到Vj 经过Vk ,最短路径序列是(Vi , …, Vk , …, Vj) ,则路径子序列:(Vi , …, Vk)和(Vk , …, Vj)一定是从Vi到Vk和从Vk到Vj 的最短路径。从而可以根据Path[i][k]和Path[k][j]的值再找到该路径上所经过的其它顶点,…依此类推。
◆ 初始化为Path[i][j]=-1,表示从Vi到Vj 不经过任何(S中的中间)顶点。当某个顶点Vk加入到S中后使A[i][j]变小时,令Path[i][j]=k。
表7-4给出了利用Floyd算法求图7-26的带权有向图的任意一对顶点间最短路径的过程。
根据上述过程中Path[i][j]数组,得出:
V0到V1 :最短路径是{ 0, 1 } ,路径长度是2 ;
V0到V2 :最短路径是{ 0, 1, 2 } ,路径长度是6 ;
V1到V0 :最短路径是{ 1, 2, 0 } ,路径长度是9 ;
V1到V2 :最短路径是{ 1, 2 } ,路径长度是4 ;
V2到V0 :最短路径是{ 2, 0 } ,路径长度是5 ;
V2到V1 :最短路径是{ 2, 0, 1 } ,路径长度是7 ;
算法实现
int A[MAX_VEX][MAX_VEX] ;
int Path[MAX_VEX][MAX_VEX] ;
void Floyd_path (AdjGraph *G)
{
int j, k, m ;
for ( j=0; j<G->vexnum; j++)
for ( k=0; k<G->vexnum; k++)
{
A[j][k]=G->adj[j][k] ;
Path[j][k]=-1 ;
}
/* 各数组的初始化 */
for ( m=0; m<G->vexnum; m++)
for ( j=0; j<G->vexnum; j++)
for ( k=0; k<G->vexnum; k++)
if ((A[j][m]+A[m][k])<A[j][k])
{
A[j][k]=A[j][m]+A[m][k] ;
Path[j][k]=k ;
} /* 修改数组A和Path的元素值 */
for ( j=0; j<G->vexnum; j++)
for ( k=0; k<G->vexnum; k++)
if (j!=k)
{
printf(“%d到%d的最短路径为:\n”, j, k) ;
printf(“%d ”,j) ; prn_pass(j, k) ;
printf(“%d ”, k) ;
printf(“最短路径长度为: %d\n”,A[j][k]) ;
}
}/* end of Floyd */
void prn_pass(int j , int k)
{
if (Path[j][k]!=-1)
{
prn_pass(j, Path[j][k]) ;
printf(“, %d” , Path[j][k]) ;
prn_pass(Path[j][k], k) ;
}
}
相关文章推荐
- GraphX中Pregel单源点最短路径
- 算法长度K最短路问题(单源点最短路径+A*算法)Strut2教程-java教程
- 单源点最短路径 c++实现 分支限界算法
- Bellman-ford算法 实现源点最短路径 允许路径中有负权值
- Dijkstra算法--有向图的源点到其他顶点的最短路径(连接矩阵、邻接矩阵两种方式)
- POJ 2449 Remmarguts' Date K最短路问题(单源点最短路径+A*算法)
- 单源点最短路径----Dijkstra算法
- 一个例子让你明白一个算法-Dijkstra(求源点到各顶点最短路径)
- 单源点最短路径--2
- 单源点最短路径算法的设计与实现
- 单源点最短路径Dijkstra算法的JAVA实现
- 图之 打印从源点到任何一个顶点最短路径所经过的顶点
- SPFA算法 快速Bellaman-ford算法 源点最短路径
- GraphX中Pregel单源点最短路径(转)
- 单源点最短路径
- 单源点最短路径-迪杰斯特拉
- 单源点最短路径
- 单源点最短路径Dijkstra方法实现
- K最短路问题(单源点最短路径+A*算法)
- 单源点最短路径Bellman算法实现