有向图中任意令两点之间的最短路径.docx
《有向图中任意令两点之间的最短路径.docx》由会员分享,可在线阅读,更多相关《有向图中任意令两点之间的最短路径.docx(9页珍藏版)》请在冰豆网上搜索。
![有向图中任意令两点之间的最短路径.docx](https://file1.bdocx.com/fileroot1/2022-10/19/a27e6de7-9557-458e-9bcb-c37d793bbb06/a27e6de7-9557-458e-9bcb-c37d793bbb061.gif)
有向图中任意令两点之间的最短路径
有向图中任意两点之间的最短路径
一.问题
求出有向图中任意两点之间的最短路径并打印结果
二.语言环境
C++
三.问题分析
要解决有向图中任意两点之间的最短路径问题首先应解决的问题是
1.从源点到其余各点的最短路径问题
2.每一对定点之间的最短路径问题
对于”从源点到其余各点的最短路径问题”有经典算法-------“迪杰斯特拉算法”.该算法的思想是:
(1).如图(A)
图(A)
路径长度最短的最短路径的特点:
在这条路径上,必定只含一条弧,并且这条弧的权值最小。
下一条路径长度次短的最短路径的特点:
它只可能有两种情况:
或者是直接从源点到该点(只含一条弧);或者是从源点经过顶点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]迪杰斯特拉算法程序段
Shortpath(MgraphG,intv0,intpath[],intdist[])
//path[v]为从v0到v的最短路径的前驱顶点,
//dist[v]为其当前的最短距离.s为全局变量,s[v]=1,
//表示v已在S集合中,即已求得从v0到v的最短距离。
{For(v=0;v{s[v]=0;dist[v]=G.arcs[v0][v];
If(dist[v]elsepath[v]=-1;//v无前驱
}
dist[v0]=0;s[v0]=1;//S集中开始时只有v0
{For(i=1;i{min=infinity;
for(w=0;wif(s[w]==0)//w∈V-S
if(dist[w]s[v]=1;//将v加入S
for(w=0;wif(s[w]==0&&(dist[v]+G.arcs[v][w]{dist[w]=dist[v]+G.arcs[v][w];
path[w]=v;
}
}
}
}
步骤
第一步
第二步
第三步
第四步
第五步
v1
∞
∞
∞
∞
∞
无
v2
10
(v0,v2)
v3
∞
60
(v0,v2,v3)
50
(v0,v4,v3)
v4
30
(v0,v4)
30
(v0,v4)
v5
100
(v0,v5)
100
(v0,v5)
90
(v0,v4,v5)
60
(v0,v4,v3,v5)
vj
v2
v4
v3
v5
S
{v0,v2}
{v0,v2,v4}
{v0,v2,v4,v3}
{v0,v2,v4,v3,v5}
对于”每一对定点之间的最短路径问题”有经典算法――弗洛伊德算法
从vi到vj的所有可能存在的路径中,选出一条长度最短的路径。
若存在,则存在路径{vi,vj}
//路径中不含其它顶点
若,存在,则存在路径{vi,v1,vj}
//路径中所含顶点序号不大于1
若{vi,…,v2},{v2,…,vj}存在,
则存在一条路径{vi,…,v2,…vj}
//路径中所含顶点序号不大于2
…
依次类推,则vi至vj的最短路径应是上述这些路径中,路径长度最小者。
如图(B)
abc
a0411
b602
c3∞0
图(B)
实现任意两点之间的最短路径的计算和显示可采用两种实验方法:
1.先采用弗洛伊德算法计算出图中所有结点之间的最短路径,将最短路径权值和最短路径路径分别存入相应的数组中,然后用户输入所要查询的两点序号,直接便可查询出最短路径权值和最短路径。
2.由迪杰斯特拉算法的思想,将所输入的节点“V1”“V2”中任意一点作为源点,运行迪杰斯特拉算法,当求出“v1”“v2”之间的最短路径之后就终止程序的运行。
(只用加入一个条件判断语句就可实现)程序如下
因为第一种算法需要求出所有点之间的最短路径,所以执行效率较低,我采用第二种算法.
四.算法实现(程序)
#include
constintmax=36727;
//创建图类
publicclassG{
intvexNum;//图中的节点总数
intarcs[][vexNum];//图的带权邻接矩阵
intdist[vexNum];//图的最短路径权值矩阵
intpath[vexNum];//用于记录最短路径的前驱顶点
public
G()//构造函数
{
vexNum=0;
}
voidinitiateArcs(intvex)//带权邻接矩阵初始化
{
vexNum=vex;
for(intj=0;jfor(intk=0;kcin<}
voidShortpath(intv1,intv2)//求任意两点之间的最短路径
//path[v]为从v0到v的最短路径的前驱顶点,
//dist[v]为其当前的最短距离.s为全局变量,s[v]=1,
//表示v已在S集合中,即已求得从v0到v的最短距离。
{
for(v=0;v{
s[v]=0;
dist[v]=arcs[v1][v];
if(dist[v]elsepath[v]=-1;//v无前驱
}
dist[v1]=0;
s[v1]=1;//S集中开始时只有v0
for(i=1;i{
intmin=max;
for(intw=0;wif(s[w]==0)//w∈V-S
if(dist[w]{
v=w;min=dist[w];
}
s[v]=1;//将v加入S
for(w=0;wif(s[w]==0&&(dist[v]+arcs[v][w]{
dist[w]=dist[v]+arcs[v][w];
path[w]=v;
}
if(v=v2)
break;
}
}
voidprintpath(intv1,intv2)//打印路径
{
coutif(v1!
=path[v2])
printpath(v1,path[v2]);
}
voidprintResult(intv1,intv2)
{
cout<<"Theshortestpathbetweenv["<";
printpath(v1,v2);
cout<<"Thevalueoftheshortestpathis:
";
cout<}
}
main()//主函数
{
Ggraph();
intv1,v2;//用户输入任意两点
intvexNum;
cout<<"InputvexNumber:
";//输入图节点总数
cin<graph.initiateArcs(vexNum);//输入图的带权邻接矩阵
cout<<"Inputtwovexes:
";//输入任意两个节点
cin<graph.shortPath(v1,v2);//求出V1、V2之间的最短路径
graph.printResult(v1,v2);//打印输出结果
return1;
}