Floyd算法的原理和实现

一.算法介绍

Floyd算法是一种在有向图中求最短路径的算法。相比不能再有向图中包含负权值的dijkstra算法,Floyd算法可以用在拥有负权值的有向图中求解最短路径(不过不能包含负权回路)。它是一种求解有向图中点与点之间最短路径的算法。

我们检查有向图中的每一个节点X,对于图中过的2点A和B,如果有Dis(AX)+Dis(XB)<Dis(AB),那么使得Dis(AB)=Dis(AX)+Dis(XB)。当所有的节点X遍历完后,AB的最短路径就求出来了。

所以,核心代码很简单,其中N是顶点个数,时间复杂度为O(N^3)

其中要注意3个for循环的嵌套顺序

void floyd(int N)
{
	int i,j,k;
	for(k=0;k<N;k++)
	{
		for(i=0;i<N;i++)
		{
			for(j=0;j<N;j++)
			{
				if(Dis[i][k]+Dis[k][j]<Dis[i][j])
				{
					Dis[i][j]=Dis[i][k]+Dis[k][j];

				}
			}
		}
	}

}

二.算法的原理

Floyd算法原理是一种动态规划的思想。

设Ak(i,j)表示从i点到j点索引号不大于K的最短路径,

则求出最短路径,可表示为

for(K=0;K<N;K++)

然后依次求A0(i,j), A1(i,j),
..., An(i,j) ,其中A0(i,j)表示初始化时候的图

在这个过程中,我们要先求A0(i,j)才能求A1(i,j),再求A2(i,j).....所以这是一种自底向上的设计思想,为什么要先求A0(i,j)才能求A1(i,j),再求A2(i,j)呢.....

因为算法的运行过程是这样的。

我们可以由Ak(i,j)求出Ak-1(i,j),那么对于Ak(i,j)来说,无外乎2种情况

第一种:

Ak(i,j)不经过点k,此时

Ak(i,j)=Ak-1(i,j)

因为对于索引号不经过k的2个点i,j,竟然经过k了,那么就应该在索引号不大于K-1里面找最短路径了

第二种:

Ak(i,j)经过了点k,此时

Ak(i,j)=Ak-1(i,k)+Ak-1(i,k)

因为经过了k,所以此时路径分2部分,一部分是从i到k,另外一部分是k,到j,因为k此时已经作为了2部分路径的起点或者终点,所以此时要求这2部分的最短路径时,就是使用Ak-1(i,k)和Ak-1(i,k)。这是一种DP的思想。

那么2种情况我最后肯定是选路径断的那一条,

所以Ak(i,j)
= min( Ak-1(i,j), Ak-1(i,k)
+ Ak-1(k,j) )

这一步其实就对应了代码部分的:

if(Dis[i][k]+Dis[k][j]<Dis[i][j])
{
   Dis[i][j]=Dis[i][k]+Dis[k][j];
}

三:打印路径

用path[i][j]纪录路径信息。

假设我们存在路径1→5→7→9,那么先求path[1][9]=7,再求path[1][7]=5,再求path[1][5]=1。

所以,算法应该改为,其中加入path[i][j]=k,因为当路径更新,该路径进过了k点,所以要纪录下来

void floyd(int N)
{
	int i,j,k;
	for(k=0;k<N;k++)
	{
		for(i=0;i<N;i++)
		{
			for(j=0;j<N;j++)
			{
				if(Dis[i][k]+Dis[k][j]<Dis[i][j])
				{
					Dis[i][j]=Dis[i][k]+Dis[k][j];
					path[i][j]=k;

				}
			}
		}
	}

}

path[i][j]初始化代码:

一开始我们假设图的任意2点都是连接的

	for(i=0;i<N;i++)
	{
		for(j=0;j<N;j++)
		{
			path[i][j]=i;
		}
	}

四:源码

该代码用邻接矩阵存储图,输入1000表示2个顶点不可达(权值无限大)

#include<iostream>
#include<stack>
using namespace std;
#define MAX 1000
int Graph[MAX][MAX];
int Dis[MAX][MAX];
#define infinite 1000
int path[MAX][MAX];

void floyd(int N)
{
	int i,j,k;
	for(k=0;k<N;k++)
	{
		for(i=0;i<N;i++)
		{
			for(j=0;j<N;j++)
			{
				if(Dis[i][k]+Dis[k][j]<Dis[i][j])
				{
					Dis[i][j]=Dis[i][k]+Dis[k][j];
					path[i][j]=k;

				}
			}
		}
	}

}

void print_path(int N)
{
	int i,j;
	for(i=0;i<N;i++)
	{
		for(j=0;j<N;j++)
		{
			if((i!=j) &&Dis[i][j]!=infinite)
			{
				cout<<i+1<<"----"<<j+1<<"   distance:"<<Dis[i][j]<<endl;
				cout<<"path:"<<endl;
				int k=j;
				stack <int> ph;
				do
				{
					k=path[i][k];
					ph.push(k);
				}while(k!=i);
				cout<<ph.top()+1;
				ph.pop();
				while(!ph.empty())
				{
					cout<<"->"<<ph.top()+1;
					ph.pop();
				}
				cout<<"->"<<j+1<<endl;
			}
		}
	}
}

void main()
{
	int N,i,j;
	cin>>N;
	for(i=0;i<N;i++)
	{
		for(j=0;j<N;j++)
		{
			int g;
			cin>>g;
			Graph[i][j]=g;
			Dis[i][j]=g;
		}
	}
//初始化路径
		for(i=0;i<N;i++)
	{
		for(j=0;j<N;j++)
		{
			path[i][j]=i;
		}
	}
	floyd(N);
	print_path(N);
    system("pause");
}

测试用的图:

测试结果:

时间: 2024-10-29 04:42:39

Floyd算法的原理和实现的相关文章

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法

44. 蛤蟆的数据结构笔记之四十四弗洛伊德Floyd算法 本篇名言:"希望是厄运的忠实的姐妹. --普希金" 我们继续来看下数据结构图中的一个算法,这个算法来自图灵奖得主. 1.  Floyd算法介绍 Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法.该算法名称以创始人之一.1978年图灵奖获得者.斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名.注意这个可不是心理学的那个弗洛伊德. 是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径

zoj1967 poj2570 Fiber Network (floyd算法)

虽然不是最短路,但是询问时任意两点之间的信息都要知道才能回答,由此联想到floyd算法,只要都floyd算法的原理理解清楚了就会发现:这道题的思想和求任意两点之间的最短路的一样的,只不过是更新的信息不同而已. 这道题还有一个难点在于状态压缩:如果直接用字符串来表示maps[i][j],那么在floyd中还需要再加一层循环来找maps[i][k]和maps[k][j]有哪些一样的字母,这样时间复杂度太高,实际测试表明会TLE.那么可以用状态压缩的技巧,用二进制表示集合,最多就26位(代表26个字母

最短路径Dijkstra算法和Floyd算法整理、

转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径—Dijkstra算法和Floyd算法 Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹

最短路径—Dijkstra算法和Floyd算法

Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径.(单源最短路径) 2.算法

Floyd算法解决多源最短路径问题

Floyd-Warshall算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包. Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2). Floyd-Warshall算法的原理是动态规划: 从i到j,要么是直接从i到j的,要么是从i出发经过中间节点到j的,假设中间节点有k种可能,那么只要求出这k种可能的最小值,即可得到最短路径. d[ i ][ j ]=min{ d[ i ][

最短路径—Floyd算法

Floyd算法 所有顶点对之间的最短路径问题是:对于给定的有向网络G=(V,E),要对G中任意两个顶点v,w(v不等于w),找出v到w的最短路径.当然我们可以n次执行DIJKSTRA算法,用FLOYD则更为直接,两种方法的时间复杂度都是一样的. 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包.Floyd-Warshall算法的时间复杂度

最短路径—大话Dijkstra算法和Floyd算法

Dijkstra算法 算法描述 1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中.在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度.此外,每个顶点对应一个距离,S中的

哈理工oj 1348 最短路径 (floyd算法)

<p>最短路径 </p><p>Time Limit: 1000 MS Memory Limit: 32767 K </p><p>Total Submit: 208(28 users) Total Accepted: 31(20 users) Rating:  Special Judge: No   Description 给出一个有向带权图G,针对该图有如下的两种操作: (1)标记该图的一个点 (2)找到两点间的只通过已标记点的最短路径长度<

vijos1635 SPFA和FLOYD算法如何打印路径

之前打的spfa或是floyd都只是用来求最短路,对于如何打印路径问题一点都没有概念 可能也是因为对于原理没有很理解的缘故? 总之,之后赶紧看了一下,现在总算是明白了.....MARK一下自己的理解 早晨碰到了一题挺裸的最短路问题:vijos1635 1.首先说说spfa的方法: 其实自己之前打的最多的spfa是在网格上的那种,也就是二维的 一维的需要邻接表+queue 以及对于queue的操作,自己也是醉了 这里贴一个模板(不含打印路径): #include<cstdio> #include