最短路径问题-Floyd算法
具体步骤和图解看这个:https://www.cnblogs.com/ssyfj/p/9495960.html
一看这个就懂了-傻子也能看懂的弗洛伊德算法:https://www.cnblogs.com/wangyuliang/p/9216365.html
知识点: 1)Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳。 2)时间复杂度比较高O(n*3),不适合计算大量数据。 3)可以算出任意两个节点之间的最短距离 4)无论是迪杰斯特拉算法还是弗洛伊德算法,对于有向图,无向图都是可以使用的。另外我们的最短路径一般都是针对有环图,无环图使用拓扑排序可以获得
5)弗洛伊德算法是用来求所有顶点到所有顶点的时间复杂度。
6)Floyd(Floyd-Warshall)算法边权可正可负,但是不能解决带有“负权回路”(或者叫“负权环”)的图,因为带有“负权回路”的图没有最短路。
7)其实如果一个图中带有“负权回路”那么这个图则没有最短路。
(如果存在一个环(从某个点出发又回到自己的路径),而且这个环上所有权值之和是负数,那这就是一个负权环,也叫负权回路)
如下图:不存在1号顶点到3号顶点的最短路径。因为1->2->3->1->2->3->...->1->2->3这样路径中,
每绕一次1->-2>3这样的环,最短路就会减少1,永远找不到最短路。
1:Floyd算法过程矩阵的计算----十字交叉法:
方法:两条线,从左上角开始计算一直到右下角 如下所示
给出矩阵,其中矩阵A是邻接矩阵,而矩阵Path记录u,v两点之间最短路径所必须经过的点
相应计算方法如下:
最后A3即为所求结果
2:实现代码
1)弗洛伊德算法定义了两个二维矩阵: 矩阵D记录顶点间的最小路径 ;例如D[0][3]= 10,说明顶点0 到 3 的最短路径为10。 矩阵P记录顶点间最小路径中的中转点 ;例如P[0][3]= 1 说明,0 到 3的最短路径轨迹为:0 -> 1 -> 3。 它通过3重循环,k为中转点,v为起点,w为终点,循环比较D0[v][w] 和 D0[v][k] + D0[k][w] 最小值,如果D0[v][k] + D0[k][w] 为更小值, 则把D0[v][k] + D0[k][w] 覆盖保存在D1[v][w]中。 2)核心思想:D1[v][w] = min{D0[v][k] + D0[k][w],D0[v][w]}【D0代表原来未更新前的数据,D1表示我们修改更新后的新的数据】
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include "queue.h" #define MAXVEX 100 //最大顶点数 #define INFINITY 65535 //用0表示∞ typedef char VertexType; //顶点类型,字符型A,B,C,D... typedef int EdgeType; //边上权值类型10,15,... //邻接矩阵结构 typedef struct { VertexType vers[MAXVEX]; //顶点表 EdgeType arc[MAXVEX][MAXVEX]; //邻接矩阵,可看作边表 int numVertexes, numEdges; //图中当前的顶点数和边数 }MGraph; typedef int Dist[MAXVEX][MAXVEX]; //存放各个顶点到其余顶点的最短路径权值和 typedef int Path[MAXVEX][MAXVEX]; //存放各个顶点到其余顶点前驱顶点位置 //创建邻接矩阵 void CreateMGraph(MGraph* G); //显示邻接矩阵 void showGraph(MGraph G); void Floyd(MGraph G,Path* path,Dist* dist); void ShowDistAndPath(Path P, Dist D,int n); void Floyd(MGraph G, Path* path, Dist* dist) { int i,j,k; //初始化path和dist for (i = 0; i < G.numVertexes;i++) { for (j = 0; j < G.numVertexes;j++) { (*dist)[i][j] = G.arc[i][j]; (*path)[i][j] = j; //初始化为这个的一个好处就是自己到自己的路径就是自己,我们不用修改 } } //使用弗洛伊德核心算法,三层循环求解 for (k = 0; k < G.numVertexes;k++) { for (i = 0; i < G.numVertexes;i++) { for (j = 0; j < G.numVertexes;j++) { if ((*dist)[i][j]>((*dist)[i][k]+(*dist)[k][j])&&i!=j) { //将权值和更新,路径也变为中转点 (*dist)[i][j] = (*dist)[i][k] + (*dist)[k][j]; (*path)[i][j] = (*path)[i][k]; } } } } } void ShowDistAndPath(Path P, Dist D,int n) { int i, j; printf("Printf Dist:\n"); for (i = 0; i < n;i++) { for (j = 0; j < n; j++) { if (i==j) printf(" 0"); //需要将我们的无穷转换一下再显示 else printf("%5d", D[i][j]); } printf("\n"); } printf("Printf Path:\n"); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) printf("%5d", P[i][j]); printf("\n"); } } int main() { MGraph MG; CreateMGraph(&MG); showGraph(MG); Path path; Dist dist; Floyd(MG, &path, &dist); ShowDistAndPath(path, dist, MG.numVertexes); system("pause"); return 0; } //生成邻接矩阵 void CreateMGraph(MGraph* G) { int i, j, k, w; G->numVertexes = 9; G->numEdges = 16; //读入顶点信息 G->vers[0] = 'A'; G->vers[1] = 'B'; G->vers[2] = 'C'; G->vers[3] = 'D'; G->vers[4] = 'E'; G->vers[5] = 'F'; G->vers[6] = 'G'; G->vers[7] = 'H'; G->vers[8] = 'I'; //getchar(); //可以获取回车符 for (i = 0; i < G->numVertexes; i++) for (j = 0; j < G->numVertexes; j++) G->arc[i][j] = INFINITY; //邻接矩阵初始化 //创建了有向邻接矩阵 G->arc[0][1] = 1; G->arc[0][2] = 5; G->arc[1][2] = 3; G->arc[1][3] = 7; G->arc[1][4] = 5; G->arc[2][4] = 1; G->arc[2][5] = 7; G->arc[3][4] = 2; G->arc[3][6] = 3; G->arc[4][5] = 3; G->arc[4][6] = 6; G->arc[4][7] = 9; G->arc[5][7] = 5; G->arc[6][7] = 2; G->arc[6][8] = 7; G->arc[7][8] = 4; for (i = 0; i < G->numVertexes;i++) for (k = i; k < G->numVertexes;k++) G->arc[k][i] = G->arc[i][k]; } //显示邻接矩阵 void showGraph(MGraph G) { for (int i = 0; i < G.numVertexes; i++) { for (int j = 0; j < G.numVertexes; j++) { if (G.arc[i][j] != INFINITY) printf("%5d", G.arc[i][j]); else printf(" 0"); } printf("\n"); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?