论没钱加油的车如何走到终点-最短路

定义外的一些补充:

  • 对于边权为正的图,任意两个结点之间的最短路,不会经过重复的结点。

  • 对于边权为正的图,任意两个结点之间的最短路,不会经过重复的边。

  • 对于边权为正的图,任意两个结点之间的最短路,任意一条的结点数不会超过 \(n\),边数不会超过 \(n-1\)

以上三条补充,都提到了“对于边权为正的图”.
那么不妨考虑一下“对于边权出现负数的图”,如果边权为负,
就意味着,可以重复走一条边来实现”刷步数“的操作,如果是这样,
那么最短路最终为无穷小.因为没有刷边,所以每条边就走一次.

Floyd:

虽然复杂度达到了 \(O(n^3)\),但该算法可以求图中
任意两点的最短路.不过前提条件是不能出现负环.

实现:

原始形式:定义三维数组 $dp\left [ k\right ] \left [ x\right ] \left [ y \right ] $ ,表示只允许经过前 \(k\) 个节点,节点 \(x\)\(y\) 的最短路径.

有了定义,如何求出 $dp\left [ k\right ] \left [ x\right ] \left [ y \right ] $ 的值呢?

首先,对于任意 \(dp\left[0\right]\left[x\right]\left[y\right]\) 的值,我们是可以立马求出来的,即0,\(x\)\(y\) 的边权,或正无穷.

以下是分组讨论:

  • x与y的边权:当x与y之间有直接边相连.

  • 0:当x与y为同一节点.

  • 正无穷:因为k为0,所以此时无法到达.

再接,对于任意 $dp\left [ k\right ] \left [ x\right ] \left [ y \right ] $ ,方程为dp[k][x][y] = min(dp[k-1][x][y], dp[k-1][x][k] + dp[k-1][k][y]).

下面对min函数内做解释.

  • dp[k-1][x][y]:即只能走前k-1个节点,如果当前可以走k号节点没有做到更短,则沿用旧的路线.

  • dp[k-1][x][k] + dp[k-1][k][y]:即相当于走k号节点,将两段部分的距离加在一起.

然而,方程中的k - 1真的有意义吗?当更新dp[k][k][x]dp[k][x][k]时,
将前者代入方程中可得到dp[k][k][x] = min(dp[k-1][k][x], dp[k-1][k][k]+dp[k-1][k][x]).
但是dp[k-1][k][k]的值为0,因此结果总是dp[k-1][k][x].根据这个例子,也能推断
后者的结论也相似.

因此,如果省略第一维,在给定的k下,每个元素的更新中使用到的元素都没有在这次迭代中更新,因此第一维的省略并不会影响结果。

丢掉第一维后,复杂度为多少呢?

  • 时间复杂度:三重循环,依次枚举k,x,y.复杂度为 \(O(n^3)\).

  • 空间复杂度:在节省了一个维度后,复杂度为 \(O(n^2)\).

模板代码:

for (k = 1; k <= n; k++) {//一定先枚举k!for (x = 1; x <= n; x++) {for (y = 1; y <= n; y++) {f[x][y] = min(f[x][y], f[x][k] + f[k][y]);}}
}

模板题:

B3647 【模板】Floyd

给出一张由 \(n\) 个点 \(m\) 条边组成的无向图。
求出所有点对 \((i,j)\) 之间的最短路径。

本题就是模板题,但要注意重边的情况.

代码:

#include<bits/stdc++.h>
using namespace std;
const int inf = 100000000;
int n,m,u,v,w,a[105][105],dp[105][105];
int main(){cin >> n >> m;while(m--){cin >> u >> v >> w;if(a[u][v]) a[u][v] = min(a[u][v],w);else a[u][v] = w;if(a[v][u]) a[v][u] = min(a[v][u],w);else a[v][u] = w;}for(int i = 1;i <= n;i++){for(int j = 1;j <= n;j++){if(!a[i][j]) dp[i][j] = inf;else dp[i][j] = a[i][j];}dp[i][i] = 0;}for(int k = 1;k <= n;k++){for(int i = 1;i <= n;i++){for(int j = 1;j <= n;j++){dp[i][j] = min(dp[i][j],dp[i][k] + dp[k][j]);}}}for(int i = 1;i <= n;i++){for(int j = 1;j <= n;j++) cout<<dp[i][j]<<" ";cout<<'\n';}
}

Dijkstra:

Dijkstra虽然是用来解决单个节点到其他节点的最短路径,
但是它的方法绝不会像隔壁的Floyd那般粗鲁.

Dijkstra朴素算法复杂度为 \(O(n^2)\),但在优先队列优化后为 \(O((n\;+\;m)\,log\,n)\).

以下为算法流程:

1.将选定的节点加入集合.

补:每个节点都拥有一个dis值,选定节点dis值为0,其他为正无穷.

2.挑选集合中dis值最小的节点,对其直接连接的所有边进行松弛操作.

松弛步骤如下:

1.假设集合中节点为 \(u\),其连接节点为 \(v\) ,之间边权为 \(w\).
若满足 \(dis\left [v\right ]\;>\;dis\left [u\right ]\;+\;w\),则更新 \(dis\left [v\right ]\) 的值,并将v加入至集合中.

2.一直持续下去,直到所有被连接的节点都完成了操作.

3.进行完松弛操作后,将该节点从集合中删除,然后重复步骤2,直到集合中无节点.

该算法朴素做法是在每次松弛操作结束后,暴力寻找集合中dis值最小的元素.
将所有步骤2都执行完后复杂度为 \(O(m)\) (即边的数量),步骤1为 \(O(n^2)\),
加起来最终复杂度为 \(O(n^2\;+\;m)\;=\;O(n^2)\)

关于“查找最小”这个操作,我们可以对其进行优化.由于本人实力有限QAQ,所以
采用优先队列优化.通过维护一个小根堆,来做到队首元素始终为最小.优化过后,
复杂度为 \(O(m\,log\,n)\) .

模板例题:

P4779 【模板】单源最短路径(标准版)

给定一个n个点,m条有向边的带非负权图,请你计算从s出发,到每个点的距离。

代码:

#include<bits/stdc++.h>
using namespace std;
bool vis[100005];
int n,m,s,dis[100005];
struct edge{int to,w;
};
struct node{int v,dis;node(int a,int b){v = a,dis = b;}bool operator <(const node &u)const {return dis > u.dis;}
};
priority_queue<node> q;
vector<edge> G[100005];
int main(){
// 	freopen("test.in","r",stdin);
//     freopen("test.out","w",stdout);cin >> n >> m >> s;for(int i = 1;i <= n;i++) dis[i] = 1e9 + 7;dis[s] = 0;while(m--){int u , v , w;cin >>u >> v >> w;edge t = {v,w};G[u].push_back(t);}q.push({s,0});while(!q.empty()){node tmp = q.top();q.pop();if(vis[tmp.v]) continue;vis[tmp.v] = 1;dis[tmp.v] = tmp.dis;for(int i = 0;i < G[tmp.v].size();i++){if(vis[G[tmp.v][i].to]) continue;if(dis[G[tmp.v][i].to] > dis[tmp.v] + G[tmp.v][i].w)q.push({G[tmp.v][i].to,dis[tmp.v] + G[tmp.v][i].w}); }}for(int i = 1;i <= n;i++) cout<<dis[i]<<" ";return 0;
}

当然,如果遇到了边权出现负数的情况,Dijkstra也只能无能狂怒.

参考文献:

OIwiki-最短路

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

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

相关文章

Spring AI + Ollama 实现 deepseek-r1 的API服务和调用

最近DeepSeek开源了对openai-o1的第一代开源推理大模型:deepseek-r1,因其极低的成本和与openai-o1相当的性能引发了国内外的激烈讨论。DD在做独立产品的时候也一直都有用DeepSeek的API来实现一些功能,比如:TransDuck中的字幕翻译、视频翻译,效果也是非常不错的。但是,最近…

OceanBase数据库SQL优化案例一则

一、现象 开发人员反馈同一条sql,sql中where条件in的值的个数不同,执行效率差异巨大。以下是截取的sql的一部分,sql中in的值的个数为为2个或3个时执行时间超过40s,in的值的个数为为1个或大于3个时不到1秒就可以返回执行结果。二、原因分析 看到这种现象,最开始怀疑是数据库…

数据库服务器 SQL Server 版本升级公告

祝大家春节快乐 !在明天(1月28日)的辞旧迎新之际,我们也安排了对园子的数据库服务器进行一次辞旧迎新,从 SQL Server 2016 升级至 SQL Server 2022。 我们使用的是阿里云 RDS 云数据库服务,升级将会由 RDS 自动完成,但在升级过程中的切换阶段会造成有段时间不能正常访问…

两种方式让你用Python轻松在RDKX5上部署推理

作者:SkyXZ CSDN:SkyXZ~-CSDN博客 博客园:SkyXZ - 博客园 宿主机环境:WSL2-Ubuntu22.04+Cuda12.6、D-Robotics-OE 1.2.8、Ubuntu20.04 GPU Docker 端侧设备环境:RDK X5-Server-3.1.0 2025年随着RDK X5的发布,地瓜官方随之也开放了RDK系列DNN推理部署的Python版的…

01. 初识Linux系统

一、什么是Ubuntu系统Ubuntu 操作系统是属于 Linux 操作系统中的一种,它是免费、稳定又可以拥有绚丽界面的一个操作系统。Linux,一般指 GNU/Linux(单独的 Linux 内核并不可直接使用,一般搭配 GNU 套件,故得此称呼),是一种免费使用和自由传播的类 UNIX 操作系统,其内核由…

学习elemetnPlus

学习了elementplus 学习了一个小时 其实就是查文档 做前端

20221320冯泰瑞-实验四密码模块应用实践过程记录

20221320冯泰瑞-实验四密码模块应用实践过程记录 实践要求完成电子公文交换系统,系统功能,(15 分)mindmaproot((电子公文系统))发文公文起草公文查看发文审核(审核员)公文发送公文查询收文公文签收公文查看公文处理公文查询系统管理组织单位用户管理操作员(科员)审核员…

android抓包相关操作指令

adb start-server adb connect 127.0.0.1:16384 adb rootadb shell su # 如果需要root权限mount -o remount,rw /systemadb push D:\\文档\\sixdu文档\\269953fb.0 /data/local/tmp adb push D:\\文档\\sixdu文档\\43b5e6bf.0 /data/local/tmpadb -s emulator-5554 push D:\\文…

四.1 Redis 五大数据类型/结构的详细说明/详细使用(List 列表数据类型详解和使用)

四.1 Redis 五大数据类型/结构的详细说明/详细使用(List 列表数据类型详解和使用) @目录四.1 Redis 五大数据类型/结构的详细说明/详细使用(List 列表数据类型详解和使用)2. list 列表常用指令(详细讲解说明)2.1 lpush/rpush <key><value1><value2>&l…

DeepSeek入门教程

一、简介 DeepSeek-V3 是一款高性能的开源 AI 模型,支持自然语言处理、智能对话生成等任务。其 API 接口与 OpenAI 完全兼容,用户可以通过简单的配置迁移现有项目,同时享受更低的成本和更高的性能。本文档将详细介绍如何快速接入 DeepSeek-V3 API 二、注册与API Key获取 1.注…

Archlinux 玩原神

首先你需要一台装载了archlinux的电脑,配置的话本人:Lenovo TianYi510S-07IMB Intel Core™ i5-10400 12 内存 8.0 GiB 磁盘 1 TB 玩的挺舒服的不会安装arch或者wine的看这里 然后本人是国际服Genshin Impact,国服同理(把下文的Genshin Impact当作yuanshen),参照官网安装…

C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)

前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。欢迎投稿、推荐或自荐优质文章、项目、学习资源等…