最短路径算法(Dijkstra算法、Floyd-Warshall算法)

最短路径算法是解决图论中节点之间最短路径问题的经典算法。以下是两种常见的最短路径算法:Dijkstra算法和Floyd-Warshall算法。

Dijkstra算法

Dijkstra算法用于解决单源最短路径问题,即给定一个起点,找到起点到其他所有节点的最短路径。

基本思想

  1. 初始化距离数组dist[],将起点到自己的距离设为0,到其余各点的距离设为无穷大(表示不可达)。
  2. 创建一个集合S,用于存放已找到最短路径的顶点,初始时集合S只包含起点。
  3. 从未加入S的顶点中选取一个距离起点最近的顶点u,加入S。
  4. 更新与u相邻的顶点的距离值:如果经过u的路径比原来已知的路径更短,则更新距离值。
  5. 重复步骤3和4,直到所有顶点都加入S为止。

特点

  • 只能用于非负权重的图。
  • 时间复杂度为O(|V|^2),其中|V|是顶点的数量。如果使用优先队列优化,时间复杂度可以降低到O(|V|log|V|+|E|),其中|E|是边的数量。

Floyd-Warshall算法

Floyd-Warshall算法用于解决多源最短路径问题,即找到任意两个顶点之间的最短路径。

基本思想

  1. 初始化一个二维数组dist[][],dist[i][j]表示顶点i到顶点j的初始距离(如果i和j之间有直接连边,则为边的权重;否则为无穷大)。
  2. 对于每一对顶点k和i,更新dist[i][j]为min(dist[i][j], dist[i][k] + dist[k][j]),即考虑经过顶点k的路径是否更短。
  3. 重复步骤2,直到dist[][]不再发生变化为止。

特点

  • 可以处理负权重的图,但不能处理负权重的环(会导致结果错误)。
  • 时间复杂度为O(|V|^3),其中|V|是顶点的数量。因此,对于大型图来说,Floyd-Warshall算法可能不是最高效的选择。

这两种算法在实际应用中都有广泛的应用,根据问题的具体需求和图的特性选择合适的算法非常重要。例如,在需要快速找到单源最短路径的情况下,Dijkstra算法可能更合适;而在需要找到任意两点之间最短路径的情况下,Floyd-Warshall算法可能更合适。

以下是使用C++分别实现Dijkstra算法和Floyd-Warshall算法的示例代码。

Dijkstra算法实现

 

cpp复制代码

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
using namespace std;
void dijkstra(vector<vector<int>>& graph, int src) {
int V = graph.size();
vector<int> dist(V, numeric_limits<int>::max()); // 初始化距离为无穷大
dist[src] = 0; // 源点距离为0
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, src}); // 将源点入队
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
for (int v = 0; v < V; ++v) {
if (graph[u][v] && dist[u] != numeric_limits<int>::max() && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
pq.push({dist[v], v});
}
}
}
// 打印结果
cout << "Vertex \t Distance from Source" << endl;
for (int i = 0; i < V; i++)
cout << i << "\t\t" << dist[i] << endl;
}
int main() {
int V = 5; // 顶点数量
vector<vector<int>> graph = {
{0, 9, 0, 0, 0},
{9, 0, 6, 0, 0},
{0, 6, 0, 3, 0},
{0, 0, 3, 0, 7},
{0, 0, 0, 7, 0}
};
int src = 0; // 源点
dijkstra(graph, src);
return 0;
}

Floyd-Warshall算法实现

 

cpp复制代码

#include <iostream>
#include <vector>
#include <limits>
using namespace std;
void floydWarshall(vector<vector<int>>& graph) {
int V = graph.size();
// dist[i][j] 将包含i到j的最短距离
vector<vector<int>> dist(V, vector<int>(V));
// 初始化dist[][]为图的权重
for (int i = 0; i < V; i++)
for (int j = 0; j < V; j++)
dist[i][j] = graph[i][j];
// 通过每个顶点作为中间点来更新dist[][]
for (int k = 0; k < V; k++) {
// Pick all vertices as source one by one
for (int i = 0; i < V; i++) {
// Pick all vertices as destination for the
// above picked source
for (int j = 0; j < V; j++) {
// If vertex k is on the shortest path from i to j,
// then update the value of dist[i][j]
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// 打印结果
cout << "Following matrix shows the shortest distances between every pair of vertices" << endl;
for (int i = 0; i < V; ++i) {
for (int j = 0; j < V; ++j) {
if (dist[i][j] == numeric_limits<int>::max())
cout << "INF" << "\t";
else
cout << dist[i][j] << "\t";
}
cout << endl;
}
}
int main() {
int V = 4; // 顶点数量
vector<vector<int>> graph = {
{0, 5, INF, 10},{5, 0, 3, INF},
{INF, 3, 0, 1},
{10, INF, 1, 0}
};
// 将INF替换为一个足够大的数,表示无穷大
const int INF = numeric_limits<int>::max();
for (auto& row : graph) {
for (auto& elem : row) {
if (elem == INF) {
elem = numeric_limits<int>::max();
}
}
}
floydWarshall(graph);
return 0;

}

在上面的Floyd-Warshall算法实现中,我使用了一个足够大的数(`numeric_limits<int>::max()`)来表示图中不存在的边(即无穷大距离)。这里假设图中不含有负权重的环,因为Floyd-Warshall算法无法正确处理这种情况。
请注意,上述代码只是两种算法的简单实现,并没有进行错误处理或优化。在实际应用中,你可能需要考虑更多因素,比如检查输入的有效性、使用更高效的数据结构、处理特殊情况等。

 

以下是使用Java实现Dijkstra算法和Floyd-Warshall算法的示例代码。

Dijkstra算法实现

 

java复制代码

import java.util.*;
public class Dijkstra {
public static void main(String[] args) {
int[][] graph = {
{0, 5, INF, 10},
{INF, 0, 3, INF},
{INF, INF, 0, 1},
{INF, INF, INF, 0}
};
int src = 0; // 源点
int V = graph.length;
dijkstra(graph, src, V);
}
private static final int INF = Integer.MAX_VALUE;
public static void dijkstra(int[][] graph, int src, int V) {
int[] dist = new int[V];
Arrays.fill(dist, INF);
dist[src] = 0;
boolean[] visited = new boolean[V];
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, visited, V);
visited[u] = true;
for (int v = 0; v < V; v++) {
if (!visited[v] && graph[u][v] != INF && dist[u] != INF && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
printSolution(dist);
}
static int minDistance(int dist[], boolean visited[], int V) {
int min = INF, min_index = -1;
for (int v = 0; v < V; v++) {
if (visited[v] == false && dist[v] <= min) {
min = dist[v];
min_index = v;
}
}
return min_index;
}
static void printSolution(int dist[]) {
System.out.println("Vertex \t Distance from Source");
for (int i = 0; i < dist.length; i++) {
System.out.println(i + "\t\t" + dist[i]);
}
}
}

Floyd-Warshall算法实现

 

java复制代码

public class FloydWarshall {
public static void main(String[] args) {
int[][] graph = {
{0, 5, INF, 10},
{INF, 0, 3, INF},
{INF, INF, 0, 1},
{INF, INF, INF, 0}
};
int V = graph.length;
floydWarshall(graph, V);
}
private static final int INF = Integer.MAX_VALUE;
public static void floydWarshall(int[][] graph, int V) {
int[][] dist = new int[V][V];
// 初始化dist[][]为图的权重
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
dist[i][j] = graph[i][j];
}
}
// 通过每个顶点作为中间点来更新dist[][]
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; 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];
}
}
}
}
// 打印结果
printSolution(dist, V);
}
static void printSolution(int[][] dist, int V) {
System.out.println("Following matrix shows the shortest distances between every pair of vertices");
for (int i = 0; i < V; i++) {
for (

int j = 0; j < V; j++) {
if (dist[i][j] == INF) {
System.out.print("INF ");
} else {
System.out.print(dist[i][j] + " ");
}
}
System.out.println();
}
}
}

 

复制代码

在上面的代码中,我们定义了两个类`Dijkstra`和`FloydWarshall`,分别实现了Dijkstra算法和Floyd-Warshall算法。`INF`是一个常量,表示无穷大,用于初始化图中不存在的边的权重。
在Dijkstra算法中,我们使用了`minDistance`方法来找到当前未访问节点中距离源点最近的节点,并更新其他节点的最短距离。最后,我们打印出所有节点到源点的最短距离。
在Floyd-Warshall算法中,我们通过一个三重循环来更新任意两点之间的最短距离。我们使用了`dist`二维数组来存储最短距离,初始时`dist[i][j]`的值等于图的权重`graph[i][j]`。然后,我们通过每个顶点作为中间点来更新`dist`数组,最终得到任意两点之间的最短距离。最后,我们打印出最短距离矩阵。
请注意,在实际使用时,你可能需要添加输入验证、错误处理以及更高效的数据结构来优化算法的性能。此外,这些代码示例假设图中没有负权重的边,因为Dijkstra算法无法处理包含负权重边的图,而Floyd-Warshall算法虽然可以处理负权重边,但如果存在负权重环,则可能导致结果不正确。在实际应用中,你需要根据具体需求和数据特性来选择合适的算法。

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

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

相关文章

【python】描述性统计计算偏斜度和峭度

文章目录 1.编写计算偏斜度和峭度的函数。并用自己编写的函数计算课本23页的习题1.5数据的偏斜度和峭度。2.从1.5数据中随机抽取2个容量为20的样本&#xff0c;分别计算它们的平均数和标准差3.请绘制给定数据的频率分布直方图&#xff0c;计算数据的均值、标准差、偏斜度和峭度…

【经典算法】 leetcode88.合并排序的数组(Java/C/Python3实现含注释说明,Easy)

作者主页&#xff1a; &#x1f517;进朱者赤的博客 精选专栏&#xff1a;&#x1f517;经典算法 作者简介&#xff1a;阿里非典型程序员一枚 &#xff0c;记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法&#xff08;公众号同名&#xff09; ❤️觉得文章还…

学习循环神经网络(RNN)

1. 掌握基础知识 理解RNN的基本概念&#xff1a;RNN是一种神经网络&#xff0c;它包含循环&#xff0c;使得网络能够维持一个内部状态&#xff0c;从而对序列的元素进行处理。学习RNN的工作机制&#xff1a;了解RNN是如何通过时间步迭代处理信息的&#xff0c;以及如何利用前一…

Ribbon 添加右侧区域菜单项

效果图如下所示&#xff1a; 类似与上图效果所示&#xff0c;代码如下&#xff1a; RibbonPage* pageHome1 ribbonBar()->addPage(tr("Home")); //实现代码&#xff1a; { QMenu* menuOptions ribbonBar()->addMenu(tr("Options"))…

古籍数字化平台:精校功能介绍

一、平台介绍 古籍数字化平台&#xff0c;本着公益性、低成本、合作共赢的三大原则&#xff0c;功能涵盖古籍OCR识别、族谱县志OCR识别、民国报纸OCR识别、图文逐字校对、数据著录、智能标点分段、精编排版、智能白话译文等&#xff0c;是一站式线上整理全流程平台。 平台集成…

C语言 【基础语法】

一、编程环境搭建 编译器&#xff1a;gcc 集成开发环境&#xff1a;vscode 1.1 安装vscode 1.2 设置中文包 插件 1.3 设置C/C扩展 安装 C/C Compile Run extension 和 C/C Extension Pack 扩展 二、基础语法 2.1 第一个c语言程序 2.2 数据类型 2.2.1 变量的语法(重点) …

Linux系统安装ansible

安装ansible yum install epel-release -y yum install ansible -y#检查是否安装成功 ansible --version检测ansible是否与其他机器连通 #需要先在/etc/ansible/hosts文件中进行配置 #并且需要配置免密登录#检测自己本机是否正常 ansible localhost -m ping #检测与主机host…

漏洞及漏洞管理

01 漏洞基础 原则上&#xff0c;漏洞是指系统或网络中的一个脆弱点&#xff0c;其可能会被网络犯罪分子利用&#xff0c;以获得未经 授权的访问&#xff0c;从而造成破坏。漏洞利用之后会发生什么呢&#xff0c;谁也说不准——安装恶意软件、 窃取敏感数据、利用恶意代码造成…

【QT进阶】Qt Web混合编程之QWebEngineView基本用法

往期回顾 【QT入门】Qt自定义控件与样式设计之自定义QTabWidget实现tab在左&#xff0c;文本水平的效果-CSDN博客【QT进阶】Qt Web混合编程之CEF、QCefView简单介绍-CSDN博客 【QT进阶】Qt Web混合编程之VS2019 CEF的编译与使用-CSDN博客 【QT进阶】Qt Web混合编程之QWebEngi…

qt 元对象系统及属性系统

Qt元对象系统(QMetaObject) Qt 的元对象系统叫 Meta-Object-System&#xff0c;提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。即使编译器不支持RTTI&#xff08;RTTI的实现耗费了很大的时间和存储空间&#xff0c;这就会降低程序的性能&#xff09;&…

URI和URL的区别?

URI&#xff08;Uniform Resource Identifier&#xff0c;统一资源标识符&#xff09;和URL&#xff08;Uniform Resource Locator&#xff0c;统一资源定位符&#xff09;都是网络上用来识别和定位资源的标准方式&#xff0c;但它们之间存在一些差异。 定义: URI 是一个用于…

MongoDB的安装使用

安装MongoDB&#xff08;基于docker安装&#xff09; docker run --restartalways -d --name mongo -v /opt/mongodb/data:/data/db -p 27017:27017 mongo:4.0.6MongoDB的客户端可以从这里下载&#xff08;可能会404&#xff09; https://www.mongodb.com/zh-cn/products/tool…

node.js-fs模块、path模块

fs模块-读写文件 模块&#xff1a;类似插件&#xff0c;封装了方法/属性 fs模块&#xff1a;封装了与本机文件系统进行交互的&#xff0c;方法/属性 语法&#xff1a; 1&#xff09;加载fs模块对象 const fsrequire(fs)//fs 是模块标识符&#xff1a;模块的名字 2&#x…

文献学习-38-用于增量组织病理学分类的内存高效提示调整

​ Memory-Efficient Prompt Tuning for Incremental Histopathology Classification Authors: Yu Zhu, Kang Li, Lequan Yu, Pheng-Ann Heng Source: The Thirty-Eighth AAAI Conference on Artificial Intelligence (AAAI-24) ​​ Abstract 最近的研究在组织病理学分类方面…

Python教学入门:流程控制

条件语句&#xff08;if 语句&#xff09;&#xff1a; 条件语句用于根据条件的真假执行不同的代码块。 x 10if x > 0: # 如果 x 大于 0print("x 是正数") # 输出&#xff1a;x 是正数 elif x 0: # 如果 x 等于 0print("x 是零") else: # 如果以…

Python教程:一文了解Python工厂模式

在软件开发中&#xff0c;一种常见的需求是根据不同条件创建不同类型的对象。工厂模式就是为了解决这个问题而设计的。它提供了一种灵活的方式来创建对象&#xff0c;同时将客户端代码与具体的对象类型解耦&#xff0c;从而使得系统更易于维护和扩展。 1.什么是工厂模式&#x…

Python基于Django的旅游城市关键词分析和提取,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【Linux系统编程】第五弹---基本指令(三)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、grep指令 2、zip/unzip指令 3、tar指令 4、bc指令 5、uname指令 6、重要的几个热键 7、拓展指令 总结 1、grep指令 …

大屏-flex布局

<div class"container"><div class"title">标题</div><div class"content"><div class"item"></div><div class"item" style"width: calc((100% - 30) / 3 * 2)"><…

C# Solidworks二次开发:程序工具界面和选项相关API详解

大家好&#xff0c;今天要讲的是关于程序工具相关的API介绍。 下面是要介绍的API: (1)第一个为GetAutoPartSimplification&#xff0c;这个API的含义为获取简化配置的指针&#xff0c;下面是官方具体解释&#xff1a; 其输入参数的类型在上一篇文章中已经介绍过了gtError_e&a…