弗洛伊德(Floyd)算法(C/C++)

简介: 弗洛伊德(Floyd)算法(C/C++)

弗洛伊德算法(Floyd's algorithm),又称为弗洛伊德-沃尔什算法(Floyd-Warshall algorithm),是一种用于在加权图中找到所有顶点对之间最短路径的算法。这个算法适用于有向图和无向图,并且可以处理负权重边,但不能处理负权重循环。

弗洛伊德算法(Floyd-Warshall Algorithm)是一种用于计算图中所有顶点对之间最短路径的动态规划算法。本文将详细介绍弗洛伊德算法的原理,并提供一个C++实现的示例,以帮助读者理解算法的工作原理和编程技巧。

算法原理

弗洛伊德算法的核心思想是通过逐步寻找并更新所有顶点对之间的最短路径来解决问题。算法使用一个距离矩阵来存储顶点之间的距离,并在每一步中考虑通过一个新的中间顶点来更新这些距离。跟上一篇Dijkstra算法一样的原理,也是通过中转点去更新最短距离。不过Floyd算法处理的是多源的最短路问题


算法步骤

  1. 初始化一个距离矩阵,其中dist[i][j]表示顶点i到顶点j的直接距离。如果ij不直接相连,则dist[i][j]为无穷大。
  2. 对于每个顶点k,作为中间顶点,更新dist[i][j]min(dist[i][j], dist[i][k] + dist[k][j])

Floyd是经典三重for循环,所以它的时间复杂度为o(n^3),n是图中顶点的数量。第一层遍历中转点,第二层遍历起点,第三层遍历终点,对于图中点的数量多的情况,Floyd算法的时间复杂度是很高的。

图解算法:

下面我们将以4个点的图进行讲解,图的连边为有向边和无向边的结合。以邻接矩阵的方式进行存储,如果大家喜欢用邻接表存储,也可以使用邻接表,下面介绍两个矩阵,矩阵A表示(i,j)i->j的最短距离,初始化为inf。矩阵B表示i->j路径由i到j的中转点,也就是路径上除去起点的第一个点,初始化为-1。

初始:

按照图中的点距离给其赋值,A矩阵i->i距离都为0,inf为无法到达。B矩阵初始为-1。

第一步:

我们选取一个点(按照顺序选取)把它作为中转点,看看以它为中转点,所能到达的点中有没有产生更小的距离,如果产生了,则更新A矩阵的距离,更新B矩阵的中转点。我们先选取1号点,那么位于1号点的行跟列的值都是不可能变化的,还有就是自己到自己的点也是不会变化的永远是0,图中黄颜色标记的是此步不会改变的点,其他的可能会变。在更新距离的时候我们可以不看图就能更新矩阵,例如下图中2号点到3号点本来为10,我们可以连一个矩阵,以1号点画的两条蓝线为两条边,红色线为剩余2边,我们既然把1号点当作中转点,路径必然为2-1-3,此时距离就是副对角线的顶点值相加2+6=8<10,那么通过1号点绕路的方式距离更短。类似的还有3->2号点,6+2=8<inf。3->4号点,10+6=16<inf。4->3号点,10+6=16<inf。顺便把B矩阵更新完。

更新完后(红色标记为变化的值):

第二步:

此时把2号结点作为中转结点,看一看能够更新哪一个最短路径,还是跟上一步一样直接看图更新就可以。如下图,4->1号点,2+4=6<10。1->4号点, 2+4=6<10。3->4号点,8+4=12<16。4->3号点,8+4=12<16。对于一些不能更新的值,例如1->3号点,2+8=10>6,这样的则不能更新。

对于B矩阵,要注意3->4跟4->3的路径是相反的,更新是则不能直接修改为2,对于3->4号点第一个中转点还是1号点。更新完后(红色标记为变化的值):

第三步:

把3号点作为中转结点,跟前几步一样,继续寻找最短距离。经过更新我们发现3号点作为中转点不能更新任意一个距离,所以A、B矩阵不需要更新。在图中,经过验证我们发现3号点中转距离反而变大,所以不更新。

第四步:

把4号点作为中转点,继续更新最短距离。我们发现跟3号点一样,不能更新任何距离,在A矩阵中除了黄色的点之外,所能连起来的矩形,主对角线顶点值相加都比当前值要大。在图中也可以验证,所以不给予更新。

这样我们就更新完所有点,把所有点都当作中转点更新完一遍,这样就完成了Floyd算法,更新时每次按照顺序把点当作中转点,遍历寻找路径的起点,再遍历寻找终点,算法时间复杂度为o(n^3)。

视频讲解可以看一下B站这位UP主的讲解,点击直达

算法实现:

以下是弗洛伊德算法的C++实现示例:

 #include <iostream>
#include <vector>
#include <limits>
using namespace std;
 
// 定义图的顶点数
const int N = 100;
// 定义无穷大的初始距离
const int INF = numeric_limits<int>::max();
 
// 弗洛伊德算法的实现
void floydWarshall(vector<vector<int>>& dist) {
    int n = dist.size();
    // 遍历所有顶点作为中间顶点
    for (int k = 0; k < n; k++) {
        // 遍历所有顶点作为起点
        for (int i = 0; i < n; i++) {
            // 遍历所有顶点作为终点
            for (int j = 0; j < n; j++) {
                // 如果通过顶点k可以找到更短的路径,则更新dist[i][j]
                if (dist[i][k] != INF && dist[k][j] != INF && dist[i][k] + dist[k][j] < dist[i][j]) {
                    dist[i][j] = dist[i][k] + dist[k][j];
                }
            }
        }
    }
}
 
int main() {
    int n; // 顶点的数量
    cin >> n;
 
    vector<vector<int>> dist(n, vector<int>(n, INF)); // 初始化距离矩阵
 
    // 读取邻接矩阵
    for (int i = 0; i < n; i++) {
        dist[i][i] = 0; // 自己到自己的距离是0
        for (int j = i; j < n; j++) {
            int w;
            cin >> w;
            dist[i][j] = w;
            dist[j][i] = w; // 如果是无向图,需要设置对称的权重
        }
    }
 
    // 执行弗洛伊德算法
    floydWarshall(dist);
 
    // 打印所有顶点对之间的最短路径
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (dist[i][j] == INF) {
                cout << "INF" << " ";
            } else {
                cout << dist[i][j] << " ";
            }
        }
        cout << endl;
    }
 
    return 0;
} 

Floyd与Dijkstra算法比较

迪杰斯特拉算法(Dijkstra's algorithm)和弗洛伊德算法(Floyd-Warshall algorithm)都是图论中用于计算图中最短路径的著名算法。它们在某些方面有相似之处,但在设计和应用上存在显著差异,下面我们将对这两种算法的相同跟不同进行解释。

相同点:
  1. 目的两者都旨在解决最短路径问题。
  2. 适用性:它们都可以用于加权图中的最短路径计算,无论是正权还是负权(只有弗洛伊德算法)。
不同点:
  1. 问题范围:
  • 迪杰斯特拉算法:主要用于单元路径的最短路问题,即从单一源点到所有其他顶点的最短路径。
  • 弗洛伊德算法:解决的是所有顶点对之间的最短路径问题,即计算图中每一对顶点之间的最短路径。
  1. 时间复杂度:
  • 迪杰斯特拉算法:具有较高的效率,时间复杂度为O(V^2)(使用朴素实现)或O((V+E) log V)(使用优先队列优化)。(V顶点E条边)
  • 弗洛伊德算法:时间复杂度为O(V^3),因为它需要计算所有顶点对的最短路径。
  1. 实现方式:
  • 迪杰斯特拉算法:通常使用贪心策略,从一个顶点开始,逐步扩展到邻接顶点,直到找到所有顶点的最短路径。
  • 弗洛伊德算法:使用动态规划,通过三层循环迭代地改进路径长度,直到达到最优解。
  1. 对负权边的处理:
  • 迪杰斯特拉算法:不能处理负权边,因为负权边会破坏算法的贪心选择性质。
  • 弗洛伊德算法:可以处理负权边,但图中不能有负权环,否则最短路径问题没有解。
  1. 初始化:
  • 迪杰斯特拉算法:从源点到其他所有顶点的距离初始化为无穷大,源点到自身的距离为0。
  • 弗洛伊德算法:所有顶点到自身的距离初始化为0,其他顶点间的距离初始化为边的权重或无穷大(如果无直接连接)。

本篇详解Floyd算法,如果想看Dijkstra算法的话,可以看博主上一篇博客,针对于Dijkstra算法的详解:迪杰斯特拉(Dijkstra)算法(C/C++)-CSDN博客

执笔至此,感触彼多,全文将至,落笔为终,感谢大家的支持。  

相关文章
|
4月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
100 2
|
6月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
167 15
|
6月前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
2月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
67 0
|
4月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
136 17
|
11月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
586 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3月前
|
机器学习/深度学习 存储 算法
基于 C++ 布隆过滤器算法的局域网上网行为控制:URL 访问过滤的高效实现研究
本文探讨了一种基于布隆过滤器的局域网上网行为控制方法,旨在解决传统黑白名单机制在处理海量URL数据时存储与查询效率低的问题。通过C++实现URL访问过滤功能,实验表明该方法可将内存占用降至传统方案的八分之一,查询速度提升约40%,假阳性率可控。研究为优化企业网络管理提供了新思路,并提出结合机器学习、改进哈希函数及分布式协同等未来优化方向。
81 0
|
5月前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
114 4
|
6月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
109 8
|
7月前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
109 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨

热门文章

最新文章