【数据结构与算法 | 图篇】Floyd-Warshall算法(多源最短路径算法)

news2024/9/20 8:15:46

1. 前言

Floyd-Warshall算法是一种在有向图或无向图中寻找所有顶点对之间的最短路径的动态规划算法。该算法可以处理带权重的边,并且能够正确处理负权重的边(但不包括负权重循环),不过它不能处理包含负权重循环的情况,因为这种情况下最短路径是没有定义的。

2. 基本原理

Floyd-Warshall算法的核心思想是逐步扩展中间顶点的集合来计算最短路径。算法通过考虑所有可能的中间顶点来更新每一对顶点之间的最短路径长度。

3. 算法步骤

1. 初始化:

  • 创建一个二维数组 `D`,其中 `D[i][j]` 表示从顶点 `i` 到顶点 `j` 的初始距离(如果 `i` 和 `j` 之间没有直接相连,则使用无穷大表示)。
  • 对于所有的直接相连的边 `(i, j)`,将 `D[i][j]` 设置为这条边的权重。
  • 对于所有的顶点 `i`,将 `D[i][i]` 设置为 0。

2. 迭代:

  • 遍历所有可能的顶点 `k` 作为中间顶点。
  • 对于每一对顶点 `(i, j)`:检查是否存在一条经过顶点 `k` 的更短路径,即检查 `D[i][k] + D[k][j]` 是否小于 `D[i][j]`。
  • 如果是,则更新 `D[i][j]` 为 `D[i][k] + D[k][j]`。

3. 检测负权重循环:
   - 在完成上述迭代之后,如果存在某个顶点 `i` 使得 `D[i][i] < 0`,则说明图中存在至少一个负权重循环。在这种情况下,算法会报告错误或者返回一个特殊值表示无法找到最短路径。

复杂度:
- 时间复杂度:O(V^3),其中 V 是顶点的数量。
- 空间复杂度:O(V^2),需要存储每个顶点对之间的最短路径长度。

4. 主要代码

顶点图:

public class FloydWarshall {
    public static void main(String[] args) {
        Vertex v1 = new Vertex("1");
        Vertex v2 = new Vertex("2");
        Vertex v3 = new Vertex("3");
        Vertex v4 = new Vertex("4");

        v1.edges = new ArrayList<>();
        v1.edges.add(new Edge(v3, -2));

        v2.edges = new ArrayList<>();
        v2.edges.add(new Edge(v1, 4));
        v2.edges.add(new Edge(v3, 3));

        v3.edges = new ArrayList<>();
        v3.edges.add(new Edge(v4, 2));

        v4.edges = new ArrayList<>();
        v4.edges.add(new Edge(v2, -1));

        List<Vertex> graph = new ArrayList<>();
        graph.add(v1);
        graph.add(v2);
        graph.add(v3);
        graph.add(v4);

        floydwarshall(graph);
    }
    public static void floydwarshall(List<Vertex> graph) {
        int size = graph.size();
        int[][] dist = new int[size][size];
        // 邻接矩阵初始化
        for (int i = 0; i < size; i++) {
            Vertex vi = graph.get(i);
            // 哈希表用来判断vi顶点的邻接点集合是否包含了vj顶点
            // 如果包含了,则dist[i][j]用边的权重表示
            // 否则用无穷大表示
            Map<Vertex, Integer> map =
            vi.edges.stream().collect(Collectors.toMap(e -> e.linked, e -> e.weight));
            for(int j = 0; j < size; j++) {
                Vertex vj = graph.get(j);
                if(vi == vj){
                    dist[i][j] = 0;
                } else {
                    dist[i][j] = map.getOrDefault(vj, Integer.MAX_VALUE);
                }
            }
        }
//        print(dist);
        // 看是否能够借路到其他顶点
        // k = 0时,其他顶点接路v1到达其他顶点
        // k = 1时,其他顶点接路v2到达其他顶点...
        // 即i的行,借助k的顶点,是否可以到达j列顶点
        for(int k = 0; k < size; k++){
            // 处理dist数组
            for(int i = 0; i < size; i++){
                for(int j = 0; j < size; j++){
                    // 假设这里的k=0, i = 1,
                    // 意思就是,v2顶点借助v1顶点是否可以到达其他顶点(v1,v2,v3,v4)
                    if(dist[i][k] != Integer.MAX_VALUE &&
                        dist[k][j] != Integer.MAX_VALUE &&
                            dist[i][k] + dist[k][j] < dist[i][j]){
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
            print(dist);
            System.out.println("----------");
        }
    }
    public static void print(int[][] dist) {
        for(int i = 0; i < 4; i++) {
            System.out.print("[");
            for(int j = 0; j < 4; j++){
                System.out.print(dist[i][j] + "  ");
            }
            System.out.print("]");
            System.out.println();
        }
    }
}

输出为:

[0  2147483647  -2  2147483647  ]
[4  0  2  2147483647  ]
[2147483647  2147483647  0  2  ]
[2147483647  -1  2147483647  0  ]
----------
[0  2147483647  -2  2147483647  ]
[4  0  2  2147483647  ]
[2147483647  2147483647  0  2  ]
[3  -1  1  0  ]
----------
[0  2147483647  -2  0  ]
[4  0  2  4  ]
[2147483647  2147483647  0  2  ]
[3  -1  1  0  ]
----------
[0  -1  -2  0  ]
[4  0  2  4  ]
[5  1  0  2  ]
[3  -1  1  0  ]
----------

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2049293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA 设置SVN项目管理忽略文件

忽略已经控制的文件 打开本地已经克隆下来的项目&#xff0c;并找到需要忽略控制的文件或文件夹 操作完成之后需要将当前的操作更新到SVN服务器。 直接在IDEA中提交修改&#xff08;快捷键CTRL K&#xff09;就可以 unverison: 取消版本控制 add to ignore list&#xff1…

C语言之文件操作上卷(二十一)(逆行人生-2024)

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; ✏️作者主页&#xff1a;枫霜剑客 &#x1f4cb; 系列专栏&#xff1a;C语言知识学习归纳总结&#xff08;逐梦篇专栏合集&#xff09; &#x1f332;上一篇: C语…

17 Menubutton 组件

17 Menubutton 组件 Tkinter 的 Menubutton 组件是一个特殊的按钮&#xff0c;当点击时会弹出一个菜单。这个菜单可以包含多个菜单项&#xff0c;允许用户从菜单中选择一个选项。Menubutton 通常用于创建带有下拉菜单的界面。以下是对 Menubutton 组件的详细说明和一个使用案例…

力控机器人torque-controlled robots

力控机器人&#xff08;Torque-Controlled Robots&#xff09;&#xff0c;也称为力矩控制机器人&#xff0c;是一种能够感知并实时控制施加在物体上力量的机器人系统。这类机器人通过集成力传感技术&#xff08;Force Sensing Technology&#xff09;和控制算法&#xff08;Co…

C++ | Leetcode C++题解之第343题整数拆分

题目&#xff1a; 题解&#xff1a; class Solution { public:int integerBreak(int n) {if (n < 3) {return n - 1;}int quotient n / 3;int remainder n % 3;if (remainder 0) {return (int)pow(3, quotient);} else if (remainder 1) {return (int)pow(3, quotient …

【CPP】继承语法详解与菱形继承

关于我&#xff1a; 睡觉待开机&#xff1a;个人主页 个人专栏: 《优选算法》《C语言》《CPP》 生活的理想&#xff0c;就是为了理想的生活! 作者留言 PDF版免费提供&#xff1a;倘若有需要&#xff0c;想拿我写的博客进行学习和交流&#xff0c;可以私信我将免费提供PDF版。…

iOS更新后在IPhone上恢复丢失的文本消息的4种方法

您是否在更新 iPhone 软件后丢失了重要的短信&#xff1f;丢失数据可能会令人沮丧&#xff0c;尤其是当它包含有价值的信息或感性信息时。幸运的是&#xff0c;有一些方法可以在iOS更新后恢复iPhone上丢失的短信。 在这篇博文中&#xff0c;我们将讨论可用于恢复丢失的短信的不…

【19. 删除链表的倒数第 N 个结点 中等】

题目&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;…

Vue学习 Day03 (hooks和路由)

自定义hooks 准备工作&#xff1a;首先导入axios的依赖 案例 首先写一个子组件&#xff0c;如下 <template> <h2>{{ sum }}</h2> <button click"addSum">点我sum1</button> <hr><img v-for"(dog,index) in dogs&qu…

Bugku-web-你必须让他停下来

打开环境&#xff0c;先分析出现的提示是让这个页面停下来 我们尝试关闭JS&#xff0c;发现确实停下来了-----》F12查看页面源代码但是flag还是没有出现&#xff0c;----》尝试刷新jpg随着刷新而变化&#xff0c;当刷新到10.jpg时flag出现 最后我尝试不关js刷新打开源代码刷新也…

展厅中控需要配套些什么设备

展厅中控系统需要配套的设备主要包括以下几个方面&#xff0c;以确保展厅内各种设备的高效管理和控制&#xff1a; 一、核心控制设备 中控主机&#xff1a; 功能&#xff1a;中控主机是展厅中控系统的核心&#xff0c;能够全面管理和控制展厅内的所有声光电设备。重要性&…

Jetpack 各种框架简介

Jetpack是Google推出的一套为Android开发提供极大便利的组件、工具和指导集&#xff0c;旨在帮助开发者快速构建高质量的应用&#xff0c;并遵循最佳实践。 Jetpack不仅是一个提高开发效率的工具集&#xff0c;还是Android开发的未来方向。它通过整合各种组件和工具&#xff0…

Easy SSSP(sssp)

目录 题目描述 输入 输出 样例输入 样例输出 提示 代码 今天的特邀网站&#xff1a; 和 题目描述 输入数据给出一个有 N 个节点&#xff0c;M 条边的带权有向图。要求你写一个程序&#xff0c;判断这个有向图中是否存在负权回路。如果从一个点沿着某条路径出发&#xff0c;又回…

【文献阅读】COUNTGD 模型结构

提出什么模块 解决什么问题 图、贡献&#xff0c;模型架构 图1 图1&#xff1a;COUNTGD能够同时使用视觉示例和文本提示来产生高度准确的对象计数&#xff08;a&#xff09;&#xff0c;但也无缝支持仅使用文本查询或仅使用视觉示例进行计数&#xff08;b&#xff09;。多模态视…

Jenkins入门以及安装

本文主要讲解&#xff0c;什么是Jenkins&#xff0c;Jenkins在Linux上如何安装。因为最近在公司&#xff0c;需要安装一套测试环境&#xff0c;便想着写了此篇文章。 什么是Jenkins Jenkins是一个开源的自动化部署工具&#xff0c;它能够持续地自动化构建、测试和部署软件项目…

尚品汇-前端(三十三)

目录&#xff1a; &#xff08;1&#xff09;面包屑处理平台属性 &#xff08;2&#xff09;排序处理 &#xff08;2&#xff09;单点登录业务介绍 &#xff08;1&#xff09;面包屑处理平台属性 前端显示&#xff1a;面包屑显示效果 搜list搜索方法继续添加返回的平台属性…

零基础5分钟上手亚马逊云科技核心云架构知识 - 权限管理最佳实践

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…

信息学奥赛初赛天天练-67-NOIP2018普及组-完善程序2-计数排序、排列、链表、单向链表、双向链表

PDF文档公众号回复关键字:20240817 1 完善程序 (单选题 &#xff0c;每小题3分&#xff0c;共30分) 最大公约数之和 对于一个 1到 n的排列 P&#xff08;即 1 到 n 中每一个数在 P中出现了恰好一次&#xff09;&#xff0c;令 q[i] 为第 i个位置之后第一个比 P[i] 值更大的位…

【数学建模】趣味数模问题-状态转移模型的应用

概述 状态转移模型结合图论&#xff0c;通过经典的智力问题展示了其在求解实际问题中的巧妙应用。虽然这些问题不需要复杂的数学知识&#xff0c;但通过建立数学模型&#xff0c;可以将其转化为标准的图论模型来解决。 问题1&#xff1a;人、狼、羊、菜渡河问题 问题描述&…