• Floyd算法基础


    弗洛伊德算法(Floyd)

    之前介绍了迪杰斯特拉算法(Dijkstra)。具体请看:最短路径算法——简单明了的迪杰斯特拉算法(Dijkstra)。Dijkstra适用于非负权图,并且一次只能从网络中找源点到任何一个节点的最短路径,而Floyd算法的应用更加广泛,可以求网络中任意两点之间的最短路径,而且弗洛伊德算法适用于负权图,这篇文章就用图和表的形式来介绍一下弗洛伊德算法!

    基本原理

    Floyd算法可以给出网络中任意两个节点之间的最短路径,因此它是比Dijkstra更一般的算法。Floyd算法的思想是将n个节点的网络表示为n行n列的矩阵,而矩阵中的元素( i , j )表示从节点i到节点j的距离dij,如果两点直接没有边相连,则相应的元素就是无穷( ∞ )

    算法步骤

    第1步:定义初始距离矩阵D0、节点序列矩阵S0 ,如下表。对角线上用”—“表示不需要从自身到自身。在这里插入图片描述
    这里的节点序列矩阵相当于路线表,如下表,Sij = j 表示从节点 i 到节点 j 只需经过节点j 即可。

    第2步:一般的第k步:令第k行为枢轴行,第k列为枢轴列。对于矩阵Dk-1 (上一步完成后的矩阵)中对的每一个元素做三重操作。

    如果满足条件:

    d ik +dkj < dij (i !=k,j !=k,i !=j)

    则进行下面的操作:

    1. 用dik + dkj 代替矩阵Dk−1 中的元素dij ,从而得到矩阵Dk
    2. 用k代替矩阵Sk−1 中的元素sij ,从而得到矩阵Sk
    3. 令k = k + 1 ,如果k = n + 1,停止,否则重复此步骤

    过程图解

    在这里插入图片描述

    对图中的网络,求任意两个节点之间的最短路径,图中弧上给出了相应节点间的距离。弧(3,5)是有向的,其他边都是双边。

    初始化配置表:
    在这里插入图片描述
    令k = 1,D0矩阵中的黄色阴影表示的第1行和第1列为枢轴行和枢轴列。

    根据三重操作发现可以改进的元素是d23 和d32 ,即
    在这里插入图片描述
    (1) d21 + d13 = 3 + 10 = 13 < ∞ 则在d23中用13 代替∞,并令s23 = 1
    (2) d31 + d12 = 10 + 3 = 13 < ∞ 则在d32中用13 代替∞,并令s32 = 1

    在这里插入图片描述
    令k = 2,D0矩阵中的黄色阴影表示的第2行和第2列为枢轴行和枢轴列。
    根据三重操作发现可以改进的元素是d14和d41,即
    在这里插入图片描述
    (1) d21 + d42 = 3 + 5 = 8 < ∞ 则在d14中用8 代替∞,并令s14 = 2
    (2) d24 + d12 = 5 + 3 = 8< ∞ 则在d41中用8 代替∞,并令s41 = 2
    在这里插入图片描述
    以此类推…

    当k = 5,D0 矩阵中的黄色阴影表示的第5行和第5列为枢轴行和枢轴列。
    根据三重操作发现没有可以改进的元素了。
    在这里插入图片描述
    这两个矩阵包含了网络中任意两个节点最短路径的所有信息。如从矩阵D中可以看出节点1到节点5的最短路径长度为12.从矩阵S中发现,节点1到节点5的中间节点是节点4,即节点1→节点4→节点5,再看节点1→节点4中间是节点2,即节点1需要通过节点2到达节点4,即节点1→节点2→节点4;而节点4可以直接到节点5,中间没有节点,因此可以得到节点1到节点5的最短路径是节点1→节点2→节点4→节点5.

    完整代码

    #include
    #include
    #include
    using namespace std;
     
    #define MAXVEX 100//最大顶点数
    typedef char VertexType;//顶点类型
    typedef int EdgeType;//边上的权值类型
    typedef struct
    {
    	VertexType vexs[MAXVEX];//顶点表
    	EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵
    	int numVertexte;//当前顶点数
    	int numEdges;//当前边数
    }MGraph;
     
    void ShortestPath_Floyd(MGraph G, vector<vector<int>>& P, vector<vector<int>>& D)
    {
    	for (int i = 0; i < G.numVertexte; ++i)
    	{
    		for (int j = 0; j < G.numVertexte; ++j)
    		{
    			D[i][j] = G.arc[i][j];//用G的邻接矩阵初始化D
    			P[i][j] = j;
    		}
     
    		for (int i = 0; i < G.numVertexte; ++i)
    		{
    			for (int j = 0; j < G.numVertexte; ++j)
    			{
    				for (int w = 0; w < G.numVertexte; ++w)
    				{
    					if (D[j][w] > D[j][i] + D[i][w])//如果经过下标为i的顶点路径比原两点间路径更短
    					{
    						D[j][w] = D[j][i] + D[i][w];//更新D的值
    						P[j][w] = P[j][i];//更新P的值
    					}
    				}
    			}
    		}
    	}
    }
     
    /*我们可以通过下面这个函数将最短路径打印出来*/
    void Print(MGraph G, vector<vector<int>>& P, vector<vector<int>>& D)
    {
    	for (int i = 0; i < G.numVertexte; ++i)
    	{
    		for (int j = i+1; j < G.numVertexte; ++j)
    		{
    			printf("v%d-v%d weight:%d ", i, j, D[i][j]);//打印源点 终点  以及他们之前的权
    			int k = P[i][j];//第一个路径顶点下标
    			printf(" path:%d", i);//打印源点
    			while (k != j)//如果没有到终点
    			{
    				printf("-> %d", k);//打印路径顶点
    				k = P[k][j];//获取下一个路径顶点下标
    			}
    			printf(" -> %d\n", j);//打印终点
    		}
    		printf("\n");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
  • 相关阅读:
    排序算法-堆排序和TopK算法
    【C++11】右值引用和移动语义
    AI智能时代:ChatGPT如何在金融市场发挥策略分析与预测能力?
    高效学习方法笔记
    从驾考科目二到自动驾驶,聊聊GPU为什么对自动驾驶很重要
    数字信号处理-08-FIR IP应用实例
    RHCE8 资料整理(七)
    自己动手从零写桌面操作系统GrapeOS系列教程——11.MBR介绍
    Ernie-SimCSE对比学习在内容反作弊上应用
    数据开发支持工具
  • 原文地址:https://blog.csdn.net/gghhb12/article/details/133235887