基于Floyd算法的最短路径问题的求解c++.docx
《基于Floyd算法的最短路径问题的求解c++.docx》由会员分享,可在线阅读,更多相关《基于Floyd算法的最短路径问题的求解c++.docx(21页珍藏版)》请在冰豆网上搜索。
基于Floyd算法的最短路径问题的求解c++
摘要
现实生活中许多实际问题的解决依赖于最短路径的应用,其中比较常用的是floyd算法。
通过floyd算法使最短路径问题变得简单化。
采用图的邻接矩阵或邻接表实现最短路径问题中图的存储。
采用VisualC++6.0的控制台工程和MFC工程分别实现基于floyd算法求最短路径的应用。
关键词:
最短路径;floyd算法;邻接矩阵;MFC工程
1需求分析
Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法。
该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。
假若要在计算机上建立一个交通咨询系统则可以采用图的结构来表示实际的交通网络。
这个资讯系统可以回答游客提出的各种问题。
例如,一位旅客要从A城到B城,他希望选择一条途中中转次数最少的路线。
假设图中每一站都需要换车,则这个问题反映到图上就是要找一条从顶点A到B所含边的数目最少的路径。
我们只需从顶点A出发对图作广度优先搜索,一旦遇到顶点B就终止。
由此所得广度优先生成树上,从根顶点A到顶点B的路径就是中转次数最少的路径,路径上A与B之间的顶点就是途径中的中转站数。
但是这只是一类最简单的图的最短路径的问题。
有时对于旅客来说,可能更关心的是节省交通费用;对于司机来说里程和速度则是他们感兴趣的信息。
为了在图上标示有关信息可对边赋以权的值,权的值表示两城市间的距离,或图中所需时间,或交通费用等等。
此时路径长度的量度就不再是路径上边的数目,而是路径上边的权值之和。
边赋以权值之后再结合最短路径算法来解决这些实际问题。
Floyd算法是最短路径经典算法中形式较为简单,便于理解的一种。
2算法基本原理
2.1邻接矩阵
邻接矩阵(AdjacencyMatrix):
是表示顶点之间相邻关系的矩阵。
设G=(V,E)是一个图,其中V={v1,v2,…,vn}。
G的邻接矩阵是一个具有下列性质的n阶方阵:
(1)对无向图而言,邻接矩阵一定是对称的,而且对角线一定为零(在此仅讨论无向简单图),有向图则不一定如此。
(2)在无向图中,任一顶点i的度为第i列所有元素的和,在有向图中顶点i的出度为第i行所有元素的和,而入度为第i列所有元素的和。
(3)用邻接矩阵法表示图共需要个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要n/2个空间。
2.2弗洛伊德算法
弗洛伊德算法使用图的邻接矩阵arcs[n+1][n+1]来存储带权有向图。
算法的基本思想是:
设置一个nxn的矩阵A(k),其中除对角线的元素都等于0外,其它元素a(k)[i][j]表示顶点i到顶点j的路径长度,K表示运算步骤。
开始时,以任意两个顶点之间的有向边的权值作为路径长度,没有有向边时,路径长度为∞,当K=0时,A(0)[i][j]=arcs[i][j],以后逐步尝试在原路径中加入其它顶点作为中间顶点,如果增加中间顶点后,得到的路径比原来的路径长度减少了,则以此新路径代替原路径,修改矩阵元素。
具体做法为:
第一步,让所有边上加入中间顶点1,取A[i][j]与A[i][1]+A[1][j]中较小的值作A[i][j]的值,完成后得到A
(1);
第二步,让所有边上加入中间顶点2,取A[i][j]与A[i][2]+A[2][j]中较小的值,完成后得到A
(2)…,如此进行下去,当第n步完成后,得到A(n),A(n)即为我们所求结果,A(n)[i][j]表示顶点i到顶点j的最短距离。
因此弗洛伊德算法可以描述为:
A(0)[i][j]=arcs[i][j];//arcs为图的邻接矩阵
A(k)[i][j]=min{A(k-1)[i][j],A(k-1)[i][k]+A(k-1)[k][j]},其中k=1,2,…,n
(1)
定义一个n阶方阵序列:
D(-1),D(0),…,D(n-1).
D(-1)[i][j]=G.arcs[i][j];
D(k)[i][j]=min{D(k-1)[i][j],D(k-1)[i][k]+D(k-1)[k][j]},k=0,1,…,n-1
(2)
其中D(0)[i][j]是从顶点vi到vj中间顶点是v0的最短路径的长度;D(k)[i][j]是从顶点vi到vj中间顶点的序号不大于k的最短路径长度;D(n-1)[i][j]是从顶点vi到vj的最短路径长度。
3类设计
3.1类的概述
类代表了某一批对象的共性和特征。
类是对象的抽象。
类这种数据类型中的数据既包含数据也包含操作数据的函数。
声明类的一般形式:
class类名
{private:
私有的数据和成员函数;
public:
公用的数据和成员函数;
};
定义对象:
类名对象名;
可以在类外定义成员函数,在函数名前加上类名,“:
:
”是作用域限定符或称作用域运算符用它说明函数式属于哪个类的。
如下面程序中的
voidMGraph:
:
CreateMGraph(MGraph&G)
{
函数体
}
3.2类的接口设计
#include
#include
#include
usingnamespacestd;
#defineMaxVertexNum100
#defineINF32767
classMGraph
{private:
charvertex[MaxVertexNum];//顶点信息
intedges[MaxVertexNum][MaxVertexNum];//邻接矩阵
intn,e;//顶点数和边数
public:
voidCreateMGraph(MGraph&);//构造有向图
voidPpath(int[][100],int,int);
voidDispath(int[][100],int[][100],int);//输出最短路径
voidFloyd(MGraphG);//Floyd算法的具体实现
};
首先将所需文件名写好,定义类MGraph。
在进行类体构造时将数据charvertex[MaxVertexNum]、intedges[MaxVertexNum][MaxVertexNum]和intn,e定义为私有数据,将成员函数voidCreateMGraph(MGraph&)、voidPpath(int[][100],int,int)、voidDispath(int[][100],int[][100],int)和voidFloyd(MGraphG)定义为公用的,以便非类体内的数据调用函数。
3.3类的实现
voidMGraph:
:
CreateMGraph(MGraph&G)//构造有向图
{
inti,j,k,p;
cout<<"请输入顶点数和边数:
";
cin>>G.n>>G.e;
cout<<"请输入顶点元素:
";
for(i=0;i{
cin>>G.vertex[i];
}
for(i=0;i{
for(j=0;j{
G.edges[i][j]=INF;
if(i==j)
{
G.edges[i][j]=0;
}
}
}
for(k=0;k{
cout<<"请输入第"<";
cin>>i>>j>>p;
G.edges[i][j]=p;
}
}
voidMGraph:
:
Ppath(intpath[][MaxVertexNum],inti,intj)//Ppath()函数在path中递归输出从顶点vi到vj的最短路径。
{
intk;
k=path[i][j];
if(k==-1)//path[i][j]=i时,顶点vi和vj之间无中间顶点,也就是说找到了始节点
{
return;
}
Ppath(path,i,k);
printf("%d",k);
Ppath(path,k,j);
}
voidMGraph:
:
Dispath(intA[][MaxVertexNum],intpath[][MaxVertexNum],intn)//输出最短路径的算法
{
inti,j;
for(i=0;i{
for(j=0;j{
if(A[i][j]==INF)
{
if(i!
=j)
{
printf("从%d到%d没有路径\n",i,j);
}
}
else
{
printf("从%d到%d=>路径长度:
%d路径:
",i,j,A[i][j]);
printf("%d,",i);
Ppath(path,i,j);
printf("%d\n",j);
}
}
}
}
voidMGraph:
:
Floyd(MGraphG)
{
intA[MaxVertexNum][MaxVertexNum],path[MaxVertexNum][MaxVertexNum];
inti,j,k;
for(i=0;i{
for(j=0;j{
A[i][j]=G.edges[i][j];
path[i][j]=-1;
}
}
for(k=0;k{
for(i=0;i{
for(j=0;j{
if(A[i][j]>A[i][k]+A[k][j])
{
A[i][j]=A[i][k]+A[k][j];
path[i][j]=k;//表示从i节点到j节点,要经过k节点
}
}
}
}
Dispath(A,path,G.n);
}
4基于控制台的应用程序
4.1主函数设计
intmain()
{
MGraphG;
G.CreateMGraph(G);
G.Floyd(G);
return0;
}
在程序的主函数部分,定义一个MGrapha类的对象G,调用成员函数CreateMGraph()和Floyd()分别完成了采用图的邻接矩阵实现最短路径问题中图的存储和采用Floyd算法求每一对顶点的最短路径的任务。
4.2运行结果及分析
将待测图的相关数据输入则得到如图1的运行结果。
图1程序运行结果
从图1可以看出:
整个程序中的矩阵存储采用的是一维数组和动态内存分配方式。
通过此类定义邻接矩阵,采用图的邻接矩阵实现最短路径问题中图的存储,然后通过主函数main调用class来实现,采用Floyd算法求每对顶点间最短路径从某个源点到其余各顶点的最短路径。
将图的基本信息输入,顶点数和边数4、8,顶点元素A、B、C、D,8条弧各自的序号和权值。
运行程序得出每对顶点间的最短路径长度和路径。
基于Floyd算法成功的解决了最短路径问题。
5基于MFC的应用程序
MFC的图形界面程序与DOS界面程序的主要不同点是:
MFC图形界面程序与DOS界面程序的输