最短路径——Floyd-Warshall算法
Floyd-Warshall算法,简称Floyd算法,用于求解任意两点间的最短距离,时间复杂度为O(n^3)。
我们平时所见的Floyd算法的一般形式如下:
void Floyd()
{
int i,j,k;
for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++)
if(dist[i][k]+dist[k][j]<dist[i][j])
dist[i][j]=dist[i][k]+dist[k][j];
}
注意下第6行这个地方,如果dist[i][k]或者dist[k][j]不存在,程序中用一个很大的数代替。最好写成if(dist[i][k]!=INF && dist[k][j]!=INF && dist[i][k]+dist[k][j]<dist[i][j]),从而防止溢出所造成的错误。
上面这个形式的算法其实是Floyd算法的精简版,而真正的Floyd算法是一种基于DP(Dynamic Programming)的最短路径算法。
例题分析:
设图G中n 个顶点的编号为1到n。令c [i, j, k]表示从i 到j 的最短路径的长度,其中k 表示该路径中的最大顶点,也就是说c[i,j,k]这条最短路径所通过的中间顶点最大不超过k。因此,如果G中包含边<i, j>,则c[i, j, 0] =边<i, j> 的长度;若i= j ,则c[i,j,0]=0;如果G中不包含边<i, j>,则c (i, j, 0)= +∞。c[i, j, n] 则是从i 到j 的最短路径的长度。 对于任意的k>0,通过分析可以得到:中间顶点不超过k 的i 到j 的最短路径有两种可能:该路径含或不含中间顶点k。若不含,则该路径长度应为c[i, j, k-1],否则长度为 c[i, k, k-1] +c [k, j, k-1]。c[i, j, k]可取两者中的最小值。 状态转移方程:c[i, j, k]=min{c[i, j, k-1], c [i, k, k-1]+c [k, j, k-1]},k>0。 这样,问题便具有了最优子结构性质,可以用动态规划方法来求解。

为了进一步理解,观察上面这个有向图:若k=0, 1, 2, 3,则c[1,3,k]= +∞;c[1,3,4]= 28;若k = 5, 6, 7,则c [1,3,k] = 10;若k=8, 9, 10,则c[1,3,k] = 9。因此1到3的最短路径长度为9。 下面通过程序来分析这一DP过程,对应上面给出的有向图:
#include <iostream>
using namespace std; const int INF = ;
int n=,map[][],dist[][][];
void init()
{
int i,j;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
map[i][j]=(i==j)?:INF;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
}
void floyd_dp()
{
int i,j,k;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
dist[i][j][]=map[i][j];
for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++){
dist[i][j][k]=dist[i][j][k-];
if(dist[i][k][k-]+dist[k][j][k-]<dist[i][j][k])
dist[i][j][k]=dist[i][k][k-]+dist[k][j][k-];
}
}
int main()
{
int k,u,v;
init();
floyd_dp();
while(cin>>u>>v,u||v)
{
for(k=;k<=n;k++)
{
if(dist[u][v][k]==INF) cout<<"+∞"<<endl;
else cout<<dist[u][v][k]<<endl;
}
}
return ;
}
Floyd-Warshall算法不仅能求出任意2点间的最短路径,还可以保存最短路径上经过的节点。下面用精简版的Floyd算法实现这一过程,程序中的图依然对应上面的有向图。
#include <iostream>
using namespace std; const int INF = ;
int n=,path[][],dist[][],map[][];
void init(){
int i,j;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
map[i][j]=(i==j)?:INF;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
map[][]=,map[][]=,map[][]=;
}
void floyd(){
int i,j,k;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
dist[i][j]=map[i][j],path[i][j]=;
for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++)
if(dist[i][k]+dist[k][j]<dist[i][j])
dist[i][j]=dist[i][k]+dist[k][j],path[i][j]=k;
}
void output(int i,int j){
if(i==j) return;
if(path[i][j]==) cout<<j<<' ';
else{
output(i,path[i][j]);
output(path[i][j],j);
}
}
int main(){
int u,v;
init();
floyd();
while(cin>>u>>v,u||v){
if(dist[u][v]==INF) cout<<"No path"<<endl;
else{
cout<<u<<' ';
output(u,v);
cout<<endl;
}
}
return ;
}
输入 1 3
输出 1 2 5 8 6 3
最短路径——Floyd-Warshall算法的更多相关文章
- Floyd—Warshall算法
我们用DP来求解任意两点间的最短路问题 首先定义状态:d[k][i][k]表示使用顶点1~k,i,j的情况下,i到j的最短路径 (d[0][i][j]表示只使用i和j,因此d[0][i][j] = c ...
- 图论之最短路径(1)——Floyd Warshall & Dijkstra算法
开始图论学习的第二部分:最短路径. 由于知识储备还不充足,暂时不使用邻接表的方法来计算. 最短路径主要分为两部分:多源最短路径和单源最短路径问题 多源最短路径: 介绍最简单的Floyd Warshal ...
- 单源最短路径——Floyd算法
正如我们所知道的,Floyd算法用于求最短路径.Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3). Floyd算法的基本思想如下:从任意 ...
- 单源最短路径Dijkstra算法,多源最短路径Floyd算法
1.单源最短路径 (1)无权图的单源最短路径 /*无权单源最短路径*/ void UnWeighted(LGraph Graph, Vertex S) { std::queue<Vertex&g ...
- 7-8 哈利·波特的考试(25 分)(图的最短路径Floyd算法)
7-8 哈利·波特的考试(25 分) 哈利·波特要考试了,他需要你的帮助.这门课学的是用魔咒将一种动物变成另一种动物的本事.例如将猫变成老鼠的魔咒是haha,将老鼠变成鱼的魔咒是hehe等等.反方向变 ...
- 最短路径问题---Dijkstra算法详解
侵删https://blog.csdn.net/qq_35644234/article/details/60870719 前言 Nobody can go back and start a new b ...
- Gym 101873D - Pants On Fire - [warshall算法求传递闭包]
题目链接:http://codeforces.com/gym/101873/problem/D 题意: 给出 $n$ 个事实,表述为 "XXX are worse than YYY" ...
- 数据结构与算法--最短路径之Bellman算法、SPFA算法
数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...
- 单源最短路径(dijkstra算法)php实现
做一个医学项目,当中在病例评分时会用到单源最短路径的算法.单源最短路径的dijkstra算法的思路例如以下: 如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点.那么( ...
- 最大流算法之EK(最短路径增广算法)
这是网络流最基础的部分--求出源点到汇点的最大流(Max-Flow). 最大流的算法有比较多,本次介绍的是其中复杂度较高,但是比较好写的EK算法.(不涉及分层,纯粹靠BFS找汇点及回溯找最小流量得到最 ...
随机推荐
- C++类的静态成员详解
类的静态成员分为静态数据成员和静态成员函数 静态数据成员 假如我们要设计一个战争游戏,游戏中有许多的兵种.游戏的过程中,每隔一段时间每个兵种都会产生,同时由于战争的消耗,每个兵种士兵的数量又会减少.为 ...
- SSIS Design7:数据类型的选择
对于SSIS的数据类型,容易遗漏精度的是DateTime,不正确的使用DateTime,time,decimal 等数据类型,可能导致溢出或数据丢失. 1,Variable 和 Parameter的D ...
- JSON和JS对象之间的互转
1. jQuery插件支持的转换方式 $.parseJSON( jsonstr ); //jQuery.parseJSON(jsonstr),可以将json字符串转换成json对象 2. 浏览器支持的 ...
- javascript 闭包
闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.因此,本文不会对闭包的概念进行大篇幅描述 ...
- Mesh Algorithm in OpenCascade
Mesh Algorithm in OpenCascade eryar@163.com Abstract. Rendering a generic surface is a two steps pro ...
- easyui中方向键、tab键、回车键
1.html中 function changeTab(event, i) { var keyCode = event.keyCode; var inputs = jQuery("#table ...
- 前端工程师技能之photoshop巧用系列第三篇——切图篇
× 目录 [1]切图信息 [2]切图步骤 [3]实战 前面的话 前端工程师除了使用photoshop进行测量之外,更重要的是要使用该软件进行切图.本文是photoshop巧用系列的第三篇——切图篇 切 ...
- ASP.NET Core的配置(1):读取配置信息
提到"配置"二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化 ...
- 如何用Node编写命令行工具
0. 命令行工具 当全局安装模块之后,我们可以在控制台下执行指定的命令来运行操作,如果npm一样.我把这样的模块称之为命令行工具模块(如理解有偏颇,欢迎指正) 1.用Node编写命令行工具 在Node ...
- Python深入06 Python的内存管理
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 语言的内存管理是语言设计的一个重要方面.它是决定语言性能的重要因素.无论是C语言的 ...