暑假,小哼准备去一些城市旅游。有些城市之间有公路,有些城市之间则没有,如下图。为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程。

上图中有4个城市8条公路,公路上的数字表示这条公路的长短。请注意这些公路是单向的。我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径。这个问题这也被称为“多源最短路径”问题。

现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组e)来存储。比如1号城市到2号城市的路程为2,则设e[1][2]的值为2。2号城市无法到达4号城市,则设置e[2][4]的值为∞。另外此处约定一个城市自己是到自己的也是0,例如e[1][1]为0,具体如下。

现在回到问题:如何求任意两点之间最短路径呢?通过之前的学习我们知道通过深度或广度优先搜索可以求出两点之间的最短路径。所以进行n2遍深度或广度优先搜索,即对每两个点都进行一次深度或广度优先搜索,便可以求得任意两点之间的最短路径。可是还有没有别的方法呢?

我们来想一想,根据我们以往的经验,如果要让任意两点(例如从顶点a点到顶点b)之间的路程变短,只能引入第三个点(顶点k),并通过这个顶点k中转即a->k->b,才可能缩短原来从顶点a点到顶点b的路程。那么这个中转的顶点k是1~n中的哪个点呢?甚至有时候不只通过一个点,而是经过两个点或者更多点中转会更短,即a->k1->k2b->或者a->k1->k2…->k->i…->b。比如上图中从4号城市到3号城市(4->3)的路程e[4][3]原本是12。如果只通过1号城市中转(4->1->3),路程将缩短为11(e[4][1]+e[1][3]=5+6=11)。其实1号城市到3号城市也可以通过2号城市中转,使得1号到3号城市的路程缩短为5(e[1][2]+e[2][3]=2+3=5)。所以如果同时经过1号和2号两个城市中转的话,从4号城市到3号城市的路程会进一步缩短为10。通过这个的例子,我们发现每个顶点都有可能使得另外两个顶点之间的路程变短。好,下面我们将这个问题一般化。

当任意两点之间不允许经过第三个点时,这些城市之间最短路程就是初始路程,如下。

假如现在只允许经过1号顶点,求任意两点之间的最短路程,应该如何求呢?只需判断e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是从i号顶点到j号顶点之间的路程。e[i][1]+e[1][j]表示的是从i号顶点先到1号顶点,再从1号顶点到j号顶点的路程之和。其中i是1~n循环,j也是1~n循环,代码实现如下。

1     for (i = 1; i <= n; i++)
2             {
3                 for (j = 1; j <= n; j++)
4                 {
5                     if (e[i][j] > e[i][1] + e[1][j])
6                         e[i][j] = e[i][1] + e[1][j];
7                 }
8             }

在只允许经过1号顶点的情况下,任意两点之间的最短路程更新为:

通过上图我们发现:在只通过1号顶点中转的情况下,3号顶点到2号顶点(e[3][2])、4号顶点到2号顶点(e[4][2])以及4号顶点到3号顶点(e[4][3])的路程都变短了。

接下来继续求在只允许经过1和2号两个顶点的情况下任意两点之间的最短路程。如何做呢?我们需要在只允许经过1号顶点时任意两点的最短路程的结果下,再判断如果经过2号顶点是否可以使得i号顶点到j号顶点之间的路程变得更短。即判断e[i][2]+e[2][j]是否比e[i][j]要小,代码实现为如下。

1 //经过1号顶点
2 for(i=1;i<=n;i++)
3 for(j=1;j<=n;j++)
4 if (e[i][j] > e[i][1]+e[1][j])  e[i][j]=e[i][1]+e[1][j];
5 //经过2号顶点
6 for(i=1;i<=n;i++)
7 for(j=1;j<=n;j++)
8 if (e[i][j] > e[i][2]+e[2][j])  e[i][j]=e[i][2]+e[2][j]; 

在只允许经过1和2号顶点的情况下,任意两点之间的最短路程更新为:

通过上图得知,在相比只允许通过1号顶点进行中转的情况下,这里允许通过1和2号顶点进行中转,使得e[1][3]和e[4][3]的路程变得更短了。

同理,继续在只允许经过1、2和3号顶点进行中转的情况下,求任意两点之间的最短路程。任意两点之间的最短路程更新为:

最后允许通过所有顶点作为中转,任意两点之间最终的最短路程为:

整个算法过程虽然说起来很麻烦,但是代码实现却非常简单,核心代码只有五行:

1     for(k=1;k<=n;k++)
2     for(i=1;i<=n;i++)
3     for(j=1;j<=n;j++)
4     if(e[i][j]>e[i][k]+e[k][j])
5                      e[i][j]=e[i][k]+e[k][j];  

这段代码的基本思想就是:最开始只允许经过1号顶点进行中转,接下来只允许经过1和2号顶点进行中转……允许经过1~n号所有顶点进行中转,求任意两点之间的最短路程。用一句话概括就是:从i号顶点到j号顶点只经过前k号点的最短路程。

1     #include 2     int main()  3     {  4     int e[10][10],k,i,j,n,m,t1,t2,t3;  5     int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值6     //读入n和m,n表示顶点个数,m表示边的条数7         scanf("%d %d",&n,&m);  8     //初始化9     for(i=1;i<=n;i++)
10     for(j=1;j<=n;j++)
11     if(i==j) e[i][j]=0;
12     else e[i][j]=inf;
13     //读入边
14     for(i=1;i<=m;i++)
15         {
16             scanf("%d %d %d",&t1,&t2,&t3);
17             e[t1][t2]=t3;
18         }
19     //Floyd-Warshall算法核心语句
20     for(k=1;k<=n;k++)
21     for(i=1;i<=n;i++)
22     for(j=1;j<=n;j++)
23     if(e[i][j]>e[i][k]+e[k][j] )
24                         e[i][j]=e[i][k]+e[k][j];
25     //输出最终的结果
26     for(i=1;i<=n;i++)
27         {
28     for(j=1;j<=n;j++)
29             {
30                 printf("%10d",e[i][j]);
31             }
32             printf("\n");
33         }
34     return 0;
35     }  

另外需要注意的是:Floyd-Warshall算法不能解决带有“负权回路”(或者叫“负权环”)的图,因为带有“负权回路”的图没有最短路。例如下面这个图就不存在1号顶点到3号顶点的最短路径。因为1->2->3->1->2->3->…->1->2->3这样路径中,每绕一次1->-2>3这样的环,最短路就会减少1,永远找不到最短路。其实如果一个图中带有“负权回路”那么这个图则没有最短路。

佛洛依德算法原理讲解相关推荐

  1. 十大常用算法之佛洛依德算法

    十大常用算法的完整实现 一.二分查找算法:https://blog.csdn.net/weixin_46635575/article/details/121532149 二.分治算法:https:// ...

  2. 最短路径算法之迪杰斯特拉算法(Dijkstra)和佛洛依德算法(Floyd)

    今天学习了这两种算法,都是用来求最小路径的算法,但是迪杰斯特拉算法只能从某个特定点到所有点的最短路径,而佛洛依德算法可以查出任意点到任意点的最小路径. 迪杰斯特拉: package dijkstra; ...

  3. 佛洛依德算法求最短路径实例

    佛洛依德算法求最短路径实例 #include <iostream> #include <string.h> #include <stdlib.h> #include ...

  4. 佛洛依德算法C语言简单实现

    计算图中每个顶点间的最短路径及路径长度 采用邻接矩阵表示图 代码如下: #include <stdio.h> #include <windows.h> #include < ...

  5. 迪杰斯特拉算法与佛洛依德算法

    迪杰斯特拉算法用于计算:某点v0到其他所有点的最短路径,时间复杂度为O(n^2) 初态: 设定V为所有顶点的集合. 设定S为已经得到的最短路径的顶点vi的集合.即S中的顶点vi,都是已经确定下来v0到 ...

  6. 推免复习之数据结构与算法 佛洛依德算法

    佛洛依德算法算法作为一个经典的求最短路径的算法,思路其实很简单,就是不停地进行"松弛操作",直到全部遍历一遍.那么什么是松弛操作呢?比如说我们的图存在一个邻接矩阵graph中,gr ...

  7. 佛洛依德算法求最短路径(记录路径信息)

    佛洛依德算法: 利用D矩阵拿到邻接矩阵中的权值.path矩阵记录两点之间的移动中转点(初始值为起点). 对于邻接矩阵中 i 到 j 点的权值进行比较,若加上一个中转点 k 后的权值小于原本的权值,则对 ...

  8. Java实现佛洛依德算法(floyd)的完整代码

    Java实现佛洛依德算法(floyd)的完整代码 /*** 弗洛伊德(floyd)算法求图中所有点对之间的最短路径:* 其中'-1'表示两点之间目前还没有联通的路径:* 结论:如果A点到G点之间有最短 ...

  9. 佛洛依德算法的学习与实现

    1.问题引入 带权有向图中单源点的最短路径问题可以用地杰斯特拉算法求解,如果要求解图中每一对顶点之间的最短路径,类似可以想到的方法为:每次以一个顶点为源点,重复执行地杰斯特拉算法算法n次,这样,便可以 ...

最新文章

  1. 【jquery】$.each的使用方法
  2. Eclipse中新建SpringBoot项目并输出HelloWorld
  3. 光纤收发器的故障处理
  4. php预编译mysql扩展_PHP-Mysqli扩展库的预编译
  5. TextBar for Mac(菜单栏增强工具)支持m1
  6. AndroidStudio配置gradle,让App自动签名
  7. “缺少winload.efi”的解决办法“:Windows Boot Manager更改读取启动信息路径
  8. 非线性光纤光学_深紫外非线性光学羟基硼酸盐的理论预言和实验验证
  9. TBtools | 多图合一至强版教程!进化树 + Motifs + 结构域 + 启动子 + 基因结构 + ....
  10. c语言char储存字符串,在c语言中char型数据在内存中的储存形式为什么
  11. mybatis plus table doesn't exists
  12. oracle数据库长连接和短连接,tcp 长连接与短连接
  13. 概率分布介绍:泊松分布
  14. 电脑系统,win7与win10到底有什么区别?
  15. 【蓝桥杯单片机(24)】历届单片机客观题及答案解析
  16. 给定一个Email地址判断是否合法
  17. JavaScript面试知识点
  18. 蓝桥杯 奥运会开幕式
  19. 好用的机电revit软件丨revit中怎么画球体,半球体,椭球体?
  20. 入手评测 r5 7530u和 r7 6800h差距 锐龙r57530u和r76800h对比

热门文章

  1. 为什么越来越多的人用集成墙整装?
  2. Android添加一个按键流程及SELinux权限问题
  3. eclipse查看项目所在文件夹
  4. 【物联网】1.物联网的基础知识
  5. 富爸爸 财务自由之路--读后感
  6. 给宽带加速,一分钟学会 屡试屡爽!
  7. 四大开源分布式存储_Kubernetes持久化存储方案测试
  8. Java使用青云客智能聊天接口做一个小助手
  9. 网络专业人士必上的十大专业网站
  10. Hexo博客之主题美化