计算完全最短路径的Floyd算法

【计算完全最短路径的Floyd算法】

(一).定义**
Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(All Paris Shortest Paths,APSP)的一种算法,是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路径的算法,同时也被用于计算有向图的传递闭包。算法的单个执行将找到所有顶点对之间的最短路径的长度(加权)。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。

(二)算法原理*
Floyd算法是一种动态规划(Dynamic Programming)算法。Floyd算法还是一个非常简单的三重循环,而且纯粹的Floyd算法的循环体内的语句也十分简洁。我们的目标就是通过遍历寻找从i点到j点的最短路径。
(1).用数组dis[i][j]来记录i,j之间的最短距离。初始化a[i][j],若i=j则a[i][j]=0,若i,j之间有边连接则a[i][j]的值为该边的权值,否则a[i][j]的值为int型的最大值65535。
(2).对所以的k值从1到n,更新任意两点之间的最短距离,计算a[i][k]+a[k][j]的值,若小于a[i][j],则a[i][j]=a[i][k]+a[k][j],否则a[i][j]的值不变。这样一来,当我们遍历完所有节点k,a[i][j]中记录的便是i到j的最短路径的距离。

(三)算法过程
1.先创建了一个结构体MGraph,两个二维数组(一个二维数组a存放顶点间的关系数据(为邻接矩阵),另一个二维数组p为路径数组)。
2.如果图中有n个顶点和m条边,初始时邻接矩阵a[i][j]表示顶点i到顶点j的权值,当i=j则a[i][j]为0,当顶点i不能到顶点j则a[i][j]为int型最大值65535。初始时通过遍历将路径矩阵p中的值全部赋值成-1。
3.如果a[i][j]>a[i][k]+a[k][j](k表示i到j路径中要经过的顶点来获取最短路径),然后在用k的值赋值给p[i][j]来标记这个最短路径要经过的点,则表示路径不是最短,需要更新。否则a[i][j]j就表示i直接到j的路径是最短的,就不需要更新了。
4.重复步骤3更新出所有路径的中间点得到最终的权值矩阵和路径矩阵。再通过递归路径数组来得到两个顶点的最短路径和最小权值。

如图为例:
在这里插入图片描述代码如下所示:

#include "iostream"
using namespace std;

#define MAXVEX 80
#define INF 65535

typedef struct
{
	int a[MAXVEX][MAXVEX];//邻接矩阵
	int p[MAXVEX][MAXVEX];//最短路径的中间点
	int numNodes;//当前顶点
	int numEdges;//当前的边数
	int weight;//权值
}MGraph;

//把图转化成邻接矩阵
void CreateMGraph(MGraph *MG)
{
	int i,j,w,n;
	
	cout<<"请输入顶点数和边数:"<<endl;
	cin>>MG->numNodes>>MG->numEdges;
	for(i=0;i<MG->numNodes;i++)
	{
	     for(j=0;j<MG->numNodes;j++)
		 {
		     MG->p[i][j]=-1;
		 }
	}

	for(i=0;i<MG->numNodes;i++)
	{
		for(j=0;j<MG->numNodes;j++)
		{
			if(i==j)
				MG->a[i][j]=0;
			else
				MG->a[i][j]=INF;//领接矩阵初始化  i不能直接到j的直接赋值成INF最大的值65535
		}
	}
	 cout<<"请输入边(Vi,Vj)的起点的下标i,终点的下标j和权值w(矩阵下标都是从0开始):"<<endl;
	for(n=0;n<MG->numEdges;n++)
	{
	   cin>>i>>j>>w;
	   MG->a[i][j]=w;
	}

	 cout<<"图转换成邻接矩阵为:"<<endl;
	for(i=0;i<MG->numNodes;i++)
	{
		for(j=0;j<MG->numNodes;j++)
		{
	       cout<<MG->a[i][j];
		   cout<<" ";
        }
		cout<<endl;
}
}

void Floyd(MGraph *MG)
{
   int i,j,k;
   for(i=0;i<MG->numNodes;i++)
   {
	   for(j=0;j<MG->numNodes;j++)
	   {
		   for(k=0;k<MG->numNodes;k++)
		   {
		      if(k==i||j==i)continue;
			  else
			  {
			     if(MG->a[j][k]>MG->a[j][i]+MG->a[i][k])
				 {
				     MG->a[j][k]=MG->a[j][i]+MG->a[i][k];
					 MG->p[j][k]=i;//标记中间到达的点i并赋值
				 }
			  }

		   }
	   }
   }
   cout<<"最短矩阵的最终结果:"<<endl;
   for(i=0;i<MG->numNodes;i++)
	{
		for(j=0;j<MG->numNodes;j++)
		{
	       cout<<MG->a[i][j];
		   cout<<" ";
        }
		cout<<endl;
}
}

void GetPathMatrix(MGraph *MG)
{
   int i,j;
   for(i=0;i<MG->numNodes;i++)
	{
	     for(j=0;j<MG->numNodes;j++)
		 {
		    cout<<MG->p[i][j]<<" ";
		 }
		 cout<<endl;
	}
}
//递归找最短路径
void Path(MGraph *MG,int x,int y)
{
    int r;
	if(MG->p[x][y]!=-1)
	{
	   r=MG->p[x][y];
	  
	   Path(MG,x,r);//通过递归从后往前找标记点 直到找到最初的标记点
	   
	   cout<<MG->p[x][y]<<"->";//显示出被标记的路径
	}
	else {
	
	}
}
//得到权值
int GetPathWeight(MGraph *MG,int x,int y)
{
   int sum;
   sum=MG->a[x][y];
   return sum;
}

int main()
{
    int i,j;
	int x,y;
	int sum=0;
    MGraph MG;

    CreateMGraph(&MG);

    Floyd(&MG);

	cout<<"得到的路径矩阵为:"<<endl;
	GetPathMatrix(&MG);

    cout<<"请输入起点和终点:";
	cin>>x>>y;
	cout<<"输出的起点到终点的最短路径:"<<endl;
	cout<<x<<"->";
	Path(&MG,x,y);
	cout<<y<<endl;

	sum=GetPathWeight(&MG,x,y);
	cout<<"最短路径的权值:";
	cout<<sum<<endl;
	system("pause");
    return 0;
}

运行结果如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值