单源最短路径——Floyd算法
正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。
Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B。所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,我们便设置Dis(AB) = Dis(AX) + Dis(XB),这样一来,当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径的距离。
很简单吧,代码看起来可能像下面这样:
for ( int i = ; i < 节点个数; ++i )
{
for ( int j = ; j < 节点个数; ++j )
{
for ( int k = ; k < 节点个数; ++k )
{
if ( Dis[i][k] + Dis[k][j] < Dis[i][j] )
{
// 找到更短路径
Dis[i][j] = Dis[i][k] + Dis[k][j];
}
}
}
}
但是这里我们要注意循环的嵌套顺序,如果把检查所有节点X放在最内层,那么结果将是不正确的,为什么呢?因为这样便过早的把i到j的最短路径确定下来了,而当后面存在更短的路径时,已经不再会更新了。
让我们来看一个例子,看下图:

图中红色的数字代表边的权重。如果我们在最内层检查所有节点X,那么对于A->B,我们只能发现一条路径,就是A->B,路径距离为9。而这显然是不正确的,真实的最短路径是A->D->C->B,路径距离为6。造成错误的原因就是我们把检查所有节点X放在最内层,造成过早的把A到B的最短路径确定下来了,当确定A->B的最短路径时Dis(AC)尚未被计算。所以,我们需要改写循环顺序,如下:
for ( int k = ; k < 节点个数; ++k )
{
for ( int i = ; i < 节点个数; ++i )
{
for ( int j = ; j < 节点个数; ++j )
{
if ( Dis[i][k] + Dis[k][j] < Dis[i][j] )
{
// 找到更短路径
Dis[i][j] = Dis[i][k] + Dis[k][j];
}
}
}
}
这样一来,对于每一个节点X,我们都会把所有的i到j处理完毕后才继续检查下一个节点。
那么接下来的问题就是,我们如何找出最短路径呢?这里需要借助一个辅助数组Path,它是这样使用的:Path(AB)的值如果为P,则表示A节点到B节点的最短路径是A->...->P->B。这样一来,假设我们要找A->B的最短路径,那么就依次查找,假设Path(AB)的值为P,那么接着查找Path(AP),假设Path(AP)的值为L,那么接着查找Path(AL),假设Path(AL)的值为A,则查找结束,最短路径为A->L->P->B。
那么,如何填充Path的值呢?很简单,当我们发现Dis(AX) + Dis(XB) < Dis(AB)成立时,就要把最短路径改为A->...->X->...->B,而此时,Path(XB)的值是已知的,所以,Path(AB) = Path(XB)。
void floyd( int _arrDis[][MAX_VERTEX_COUNT], int _arrPath[][MAX_VERTEX_COUNT], int _nVertexCount )
{
// 先初始化_arrPath
for ( int i = ; i < _nVertexCount; ++i )
{
for ( int j = ; j < _nVertexCount; ++j )
{
_arrPath[i][j] = i;
}
}
////////////////////////////////////////////////////////////////////////// for ( int k = ; k < _nVertexCount; ++k )
{
for ( int i = ; i < _nVertexCount; ++i )
{
for ( int j = ; j < _nVertexCount; ++j )
{
if ( _arrDis[i][k] + _arrDis[k][j] < _arrDis[i][j] )
{
// 找到更短路径
_arrDis[i][j] = _arrDis[i][k] + _arrDis[k][j];
_arrPath[i][j] = _arrPath[k][j];
}
}
}
}
}
测试代码,打印最短路径
#include<iostream>
#include<string>
#include<cstdlib>
#include<algorithm>
#include<climits> using namespace std; const int MAX_VERTEX_COUNT = ;
const int INFINITE = ;
int arrPath[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];
int arrDis[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT]; void floyd(int _arrDis[][MAX_VERTEX_COUNT], int _arrPath[][MAX_VERTEX_COUNT], int _nVertexCount)
{
// 先初始化_arrPath
for (int i = ; i < _nVertexCount; ++i)
{
for (int j = ; j < _nVertexCount; ++j)
{
_arrPath[i][j] = i;
}
}
////////////////////////////////////////////////////////////////////////// for (int k = ; k < _nVertexCount; ++k)
{
for (int i = ; i < _nVertexCount; ++i)
{
for (int j = ; j < _nVertexCount; ++j)
{
//cout << k << "," << i << "," << j << endl;
//cout << _arrDis[i][k] << "," << _arrDis[k][j] << "," << _arrDis[i][j] << endl;
if (_arrDis[i][k] + _arrDis[k][j] < _arrDis[i][j])
{
// 找到更短路径
_arrDis[i][j] = _arrDis[i][k] + _arrDis[k][j];
_arrPath[i][j] = _arrPath[k][j]; //cout << "_arrDis[i][j] = " << _arrDis[i][j] << endl;
//cout << "_arrPath[i][j] = " << _arrPath[i][j] << endl; }
}
}
}
} int main()
{
for (int i = ; i < MAX_VERTEX_COUNT; i++)
for (int j = ; j < MAX_VERTEX_COUNT; j++)
arrDis[i][j] = INFINITE; arrDis[][] = ;
arrDis[][] = ;
arrDis[][] = ;
arrDis[][] = ;
arrDis[][] = ;
arrDis[][] = ;
arrDis[][] = ;
arrDis[][] = ; floyd(arrDis, arrPath, MAX_VERTEX_COUNT); cout << "input two point for calculate :" << endl;
int p1, p2;
cin >> p1 >> p2;
cout << arrDis[p1][p2] << endl; int k = p2;
cout << k ;
while (k != p1)
{
cout << "->" << arrPath[p1][k];
k = arrPath[p1][k];
}
}
单源最短路径——Floyd算法的更多相关文章
- 单源最短路径Dijkstra算法,多源最短路径Floyd算法
		
1.单源最短路径 (1)无权图的单源最短路径 /*无权单源最短路径*/ void UnWeighted(LGraph Graph, Vertex S) { std::queue<Vertex&g ...
 - 单源最短路径——dijkstra算法
		
dijkstra算法与prim算法的区别 1.先说说prim算法的思想: 众所周知,prim算法是一个最小生成树算法,它运用的是贪心原理(在这里不再证明),设置两个点集合,一个集合为要求的生成树的 ...
 - 单源最短路径 dijkstra算法实现
		
本文记录一下dijkstra算法的实现,图用邻接矩阵表示,假设图为无向图.而且连通,有向图,不连通图的做法相似. 算法简述: 首先确定"单源"的源.假设是第0个顶点. 维护三个数组 ...
 - 多源最短路径Floyd算法
		
多源最短路径是求图中任意两点间的最短路,采用动态规划算法,也称为Floyd算法.将顶点编号为0,1,2...n-1首先定义dis[i][j][k]为顶点 i 到 j 的最短路径,且这条路径只经过最大编 ...
 - 单源最短路径——Dijkstra算法学习
		
每次都以为自己理解了Dijkstra这个算法,但是过没多久又忘记了,这应该是第4.5次重温这个算法了. 这次是看的胡鹏的<地理信息系统>,看完之后突然意识到用数学公式表示算法流程是如此的好 ...
 - 单源最短路径-Dijkstra算法
		
1.算法标签 贪心 2.算法描述 具体的算法描述网上有好多,我觉得莫过于直接wiki,只说明一些我之前比较迷惑的. 对于Dijkstra算法,最重要的是维护以下几个数据结构: 顶点集合S : 表示已经 ...
 - 单源最短路径---Bellman-Ford算法
		
传送门: Dijkstra Bellman-Ford SPFA Floyd 1.Dijkstra算法的局限性 像上图,如果用dijkstra算法的话就会出错,因为如果从1开始,第一步dist[2] = ...
 - 全源最短路径 - floyd算法 - O(N ^ 3)
		
Floyd-Warshall算法的原理是动态规划. 设Di,j,k为从i到j的只以(1..k)集合中的节点为中间节点的最短路径的长度. 若最短路径经过点k,则Di,j,k = Di,k,k − 1 + ...
 - 洛谷P3371单源最短路径SPFA算法
		
SPFA同样是一种基于贪心的算法,看过之前一篇blog的读者应该可以发现,SPFA和堆优化版的Dijkstra如此的相似,没错,但SPFA有一优点是Dijkstra没有的,就是它可以处理负边的情况. ...
 
随机推荐
- Sprint第二个冲刺(第六天)
			
一.Sprint 计划会议: 因为这两天课程较多的原因,表面上进度可能可能没有太大的变化,其实组员们都有完善之前做的功能,正在做的功能也在抓紧时间完成.俗话说得好,慢工出细活 ,不能因为赶进度就随便做 ...
 - POJ 3660 Cow Contest
			
题目链接:http://poj.org/problem?id=3660 Cow Contest Time Limit: 1000MS Memory Limit: 65536K Total Subm ...
 - 【HNOI2004】【P1365】L语言
			
tire水题,%Menci 原题: 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章.一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成. ...
 - Redis 源码解析
			
http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness- ...
 - Lucene 对文档打分的规则整理记录
			
摘引自:http://www.cnblogs.com/forfuture1978/archive/2010/02/08/1666137.html Lucene的搜索结果默认按相关度排序,这个相关度排序 ...
 - QQ登入(1)-有客户端直接授权,没客户端web授权
			
准备jar文件3个: android-support-v4.jar 下载地址:http://pan.baidu.com/s/1eQmoTm6 mta-sdk-1.6.2.jar 下载地址:http:/ ...
 - 如何在Unity中播放影片
			
Unity支援影片貼圖,也就是說可以匯入影片並附加到遊戲物件上,基本上您電腦上的Quick Time播放器能播的,大致上都能播,已知的支援的影片格式有下列幾種:.mov, .mpg, .mpeg, . ...
 - 基于OkHttp的封装库TigerOkHttp的使用
			
在前面熟悉了OkHttp的用法之后,为了简化用法同时适用于我的项目,我针对OkHttp进行了更进一步的封装(源码及其Demo地址在https://github.com/huyongli/TigerOk ...
 - MongoDB 入门与实例
			
一.准备工作 1. 下载mongoDB 下载地址:http://www.mongodb.org/downloads 选择合适你的版本 相关文档:http://www.mongodb.org/displ ...
 - .net framework4与其client profile版本的区别
			
简而言之,client profile版本是完整版本的一个子集.包含大多数最常用的功能并减小了体积,以便更容易的安装和发布,同时还有微软所声称的一些好处,比如因为减少了某些库,所以使其更加安全等等. ...