有向图中任意两点之间的最短路径一.问题求出有向图中任意两点之间的最短路径并打印结果二.语言环境C++三.问题分析要解决有向图中任意两点之间的最短路径问题首先应解决的问题是1.从源点到其余各点的最短路径问题2.每一对定点之间的最短路径问题对于”○1从源点到其余各点的最短路径问题”有经典算法-------“迪杰斯特拉算法”.该算法的思想是:(1). 如图(A)图(A )路径长度最短的最短路径的特点:<V0,V2,V3,V4>13 <V0,V2>2113长度最短路径<V0,V1><V0,V2,V3><V0,V2,V3,V4,V5><V0,V1,V6>81920在这条路径上,必定只含一条弧,并且这条弧的权值最小。
下一条路径长度次短的最短路径的特点:它只可能有两种情况:或者是直接从源点到该点(只含一条弧);或者是从源点经过顶点v1,再到达该顶点(由两条弧组成)。
再下一条路径长度次短的最短路径的特点:它可能有三种情况:或者是直接从源点到该点(只含一条弧);或者是从源点经过顶点v1,再到达该顶点(由两条弧组成);或者是从源点经过顶点v2,再到达该顶点。
其余最短路径的特点:它或者是直接从源点到该点(只含一条弧);或者是从源点经过已求得最短路径的顶点,再到达该顶点。
由以上特点可知:假设S为已求得最短路径的终点的集合,则可证明:下一条最短路径(设其终点为x)或者是弧(v,x),或者是中间只经过S中的顶点而最后到达终点x的路径。
假设此路径上有一个顶点不在S中,则说明存在一条终点不在S中,而长度比此路径短的路径。
但这是不可能的,因为我们是按路径长度递增的次序来产生最短路径的,故长度比此路径短的所有路径均已产生,他们的终点必定在S中,即假设不成立。
设置辅助数组Dist,其中每个分量Dist[k] 表示当前所求得的从源点到其余各顶点k 的最短路径。
一般情况下,Dist[k] = <源点到顶点 k 的弧上的权值>或者 = <源点到S中某顶点j的路径长度>+ <顶点j到顶点 k 的弧上的权值>。
(1). 在所有从原点出发的弧中选取一条权值最小的弧即为第一条最短路径(如图(a ))V0和k 之间存在弧 V0和k 之间不存在弧其中的最小值即为最短路径的长度。
(2). 修改其它各顶点的Dist [k ]值。
假设求得最短路径的顶点为u ,若 Dist [u ]+G .arcs [u ][k ]<Dist [k ] 则将 Dist [k ] 改为 Dist [u ]+G .arcs [u ][k ]。
迪杰斯特拉算法程序段Shortpath(Mgraph G ,int v0, int path[], int dist[]) //path[v]为从v0到v 的最短路径的前驱顶点, //dist[v]为其当前的最短距离.s 为全局变量,s[v]=1,//表示v 已在S 集合中,即已求得从v0到v 的最短距离。
{ For(v=0;v<G .vexnum;++v){ s[v]=0; dist[v]=G .arcs[v0][v];If(dist[v]<infinity) path[v]=v0; //v0是v 的前驱 else path[v]=-1; //v 无前驱 }dist[v0]=0; s[v0]=1; //S 集中开始时只有v0 { For(i=1;i<G .vexnum;++i){ min=infinity;for(w=0;w<G .vexnum;++w) if(s[w]==0) //w ∈V-Sif(dist[w]<min) {v=w; min=dist[w];}s[v]=1; //将v 加入Sfor(w=0;w<G .vexnum;++w) //调整其余在V-S 的点 if(s[w]==0 &&(dist[v]+G .arcs[v][w]<dist[w])) { dist[w]= dist[v] + G .arcs[v][w]; path[w]=v; } } } }⎩⎨⎧=INFINITYk v arcs G k Dist ]][0[.][对于” ○2每一对定点之间的最短路径问题”有经典算法――弗洛伊德算法 从 vi 到 vj 的所有可能存在的路径中,选出一条长度最短的路径。
若<vi,vj>存在,则存在路径{vi,vj}// 路径中不含其它顶点 若<vi,v1>,<v1,vj>存在,则存在路径{vi,v1,vj}∞ ∞ 10 ∞ 30 100 ∞ ∞ 5 ∞ ∞ ∞ ∞ ∞ ∞ 50 ∞ ∞ ∞ ∞ ∞ ∞ ∞ 10 ∞ ∞ ∞ 20 ∞ 60 ∞ ∞ ∞ ∞ ∞ ∞// 路径中所含顶点序号不大于1 若{vi,…,v2}, {v2,…,vj}存在, 则存在一条路径{vi, …, v2, …vj} // 路径中所含顶点序号不大于2 …依次类推,则 vi 至 vj 的最短路径应是上述这些路径中,路径长度最小者。
如图(B )a b ca0 4 11b 6 0 2c 3 ∞ 0图(B )实现任意两点之间的最短路径的计算和显示可采用两种实验方法:1. 先采用弗洛伊德算法计算出图中所有结点之间的最短路径,将最短路径权值和最短路径路径分别存入相应的数组中,然后用户输入所要查询的两点序号,直接便可查询出最短路径权值和最短路径。
2. 由迪杰斯特拉算法的思想,将所输入的节点“V1” “V2”中任意一点作为源点,运行迪杰斯特拉算法,当求出“v1”“v2”之间的最短路径之后就终止程序的运行。
(只用加入一个条件判断语句就可实现) 程序如下 因为第一种算法需要求出所有点之间的最短路径,所以执行效率较低,我采用第二种算法.a b四.算法实现(程序)#include <iostream.h>const int max=36727;//创建图类public class G{int vexNum; //图中的节点总数int arcs[][vexNum]; //图的带权邻接矩阵int dist[vexNum]; //图的最短路径权值矩阵int path[vexNum]; //用于记录最短路径的前驱顶点publicG() //构造函数{vexNum=0;}void initiateArcs(int vex) //带权邻接矩阵初始化{vexNum= vex;for(int j=0; j<vexNum; ++j)for(int k=0; k<vexNum; ++k)cin << arcs[j][k];}void Shortpath(int v1,int v2 ) //求任意两点之间的最短路径//path[v]为从v0到v的最短路径的前驱顶点,//dist[v]为其当前的最短距离.s为全局变量,s[v]=1,//表示v已在S集合中,即已求得从v0到v的最短距离。
{for (v=0; v<vexnum; ++v){s[v]=0;dist[v]=arcs[v1][v];if (dist[v]<infinity) path[v]=v0; //v0是v的前驱else path[v]=-1; //v无前驱}dist[v1]=0;s[v1]=1; //S集中开始时只有v0for (i=1; i<vexnum; ++i){int min=max;for (int w=0; w<vexnum; ++w)if (s[w]==0) //w∈V-S if(dist[w] < min){v=w; min=dist[w];}s[v]=1; //将v加入Sfor(w=0;w < vexnum; ++w) //调整其余在V-S的点if(s[w] == 0 && (dist[v] + arcs[v][w] < dist[w])){dist[w]= dist[v] + arcs[v][w];path[w]=v;}if(v = v2)break;}}void printpath(int v1,int v2) //打印路径{cout < path[v2]<< "--"; //运用第归if (v1 != path[v2])printpath(v1,path[v2]);}void printResult ( int v1,int v2){cout << "The shortest path between v["<< v1<< "] and v["<< v2<< "] is:";printpath(v1,v2);cout << "The value of the shortest path is:";cout << dist[v1][v2]<< endl;}}main() //主函数{G graph();int v1,v2; //用户输入任意两点int vexNum;cout << "Input vexNumber :"; //输入图节点总数cin << vexNum;graph.initiateArcs(vexNum); //输入图的带权邻接矩阵cout << "Input two vexes:"; //输入任意两个节点cin << v1<< v2;graph.shortPath(v1,v2); //求出V1、V2之间的最短路径graph.printResult(v1,v2); //打印输出结果return 1;}。