当前位置: 首页 > news >正文

全源最短路问题

全源最短路问题

0xFF 引入

上回讲了 单源最短路 可有许多问题没有给出起点这可怎么办呢?

0x01 Floyd-Warshall

问题

Floyd-Warshall 简称 Floyd 又叫 插点法 其实本质上是 dp

$dp_{i,j,k} $ 表述 从 \(i\)\(j\) 经过 \(k\) 的最短路长度

状态说完了 接下来是边界 可以发现 \(dp_{i,j,0}=(i,j)\)

最后就是状态转移方程

\[dp_{i,j,k}=\min(dp_{i,j,k-1},dp_{i,k,k-1}+dp_{k,j,k-1}) \]

刷过题的都看的出来可以用滚动数组来优化掉第三维

\[dp_{i,j}=\min(dp_{i,j},dp_{i,k}+dp_{k,j}) \]

这样我们就发明出了 Floyd 算法

code:

//LG
//【模板】Floyd
//https://www.luogu.com.cn/problem/B3647
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
ll G[110][110];
ll dp[110][110];
int n,m;
int main(){cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dp[i][j]=G[i][j]=(i==j?0:INT_MAX);while(m--){int u,v;ll w;cin>>u>>v>>w;dp[u][v]=G[u][v]=min(G[u][v],w);dp[v][u]=G[v][u]=min(G[v][u],w);}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";}return 0;
}
注意

这里的 k 是阶段所以一定要在最外层

0x02 Johnson

现在的你:

这也太简单了吧

那请看题

好你马上打了个 Floyd 等等...

\(n \le 3 \times 10^3\) 那 Floyd 就大约要 \(27000000000\) 根据 1秒 1e6 1兆1e5 那要 \(27s\)

那跑 \(n\) 次 Dijkstra ?

有负权

啊啊啊

聪明的你一定会想到这种方法

那就是给每条边加上一个大的数

好吧 这是错的

因为你的边越多 加的数就越多

那要怎么做呢?

0x01 \(h\) 数组 势能数组

我们可以建造一个 超级源点 比如 \(0\) 接下来以 超级源点 作为 \(s\) 跑一遍 SPFA 同时判断是否有负环 同时把这次的最短路记为 \(h\) 我们把它叫做 势能数组

0x02 重新建图

接下来我们把 \((u,v)+h_u-h_v\) 当做新的 \((u,v)\)

然后做 \(n\) 次 Dijkstra 如果第 \(i\)\(v\) 的最短路是 \(l_v\) 那真正的最短路就是 \(l_v-h_i+h_v\)

code:

//LG
//【模板】全源最短路(Johnson)
//https://www.luogu.com.cn/problem/P5905
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct e{int u,v;ll w;
};
vector<e> G[3010];
vector<e> nG[3010];
int n,m;
vector<ll> h;
bool SPFA(){h[0]=0;vector<int> cnt(n+10,0);vector<bool> f(n+10,1);f[0]=0;queue<int> q;q.push(0);while(q.size()){int u=q.front();q.pop();f[u]=1;for(int i=0;i<G[u].size();i++){int v=G[u][i].v;ll w=G[u][i].w;if(h[v]>h[u]+w){cnt[v]=cnt[u]+1;if(f[v])q.push(v);h[v]=h[u]+w;}if(cnt[v]>n)return 0;}}return 1;
}
ll Dijkstra(int s){vector<ll> l(n+10,1e9);l[s]=0;vector<bool> f(n+10,1);priority_queue<pair<ll,int> > q;q.push(make_pair(0,s));while(q.size()){int u=q.top().second;q.pop();if(f[u]){f[u]=0;for(int i=0;i<nG[u].size();i++){int v=nG[u][i].v;ll w=nG[u][i].w;if(l[v]>l[u]+w){l[v]=l[u]+w;q.push(make_pair(-l[v],v));}}}}ll ans=0;for(ll i=1;i<=n;i++){if(f[i])ans+=i*1000000000;else ans+=i*(l[i]-h[s]+h[i]);}return ans;
}
void Johnson(){for(int i=1;i<=n+10;i++)h.push_back(1e9);for(int i=1;i<=n;i++)G[0].push_back({0,i,0});if(SPFA()==0){cout<<-1;}else{for(int i=1;i<=n;i++){for(int j=0;j<G[i].size();j++){int u=i,v=G[i][j].v;ll w=G[i][j].w+h[u]-h[v];nG[u].push_back({u,v,w});}}for(int i=1;i<=n;i++)cout<<Dijkstra(i)<<"\n";}
}
ll g[3010][3010];
int main(){cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)g[i][j]=(i!=j?1e9:0);while(m--){int u,v;ll w;cin>>u>>v>>w;g[u][v]=min(g[u][v],w);}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(g[i][j]!=1e9)G[i].push_back({i,j,g[i][j]});Johnson();return 0;
}

0x03 证明

许多证明都用到了 whk 的势能可世界上有小学生啊!!!

所以小学生版的证明来了

假设 \(s\)\(t\) 的路径是

\[s , p_1 , p_2 , p_3 , \cdots ,t \]

那边权和就是

\[((s,p_1)+h_s-h_{p_1})+((p1,p_2)+h_{p_1}-h_{p_2})+((p_2,p_3)+h_{p_2}-h_{p_3}) + \cdots +((p_n,t)+h_{p_n}-h_t) \]

化简得

\[(s,p_1)+(p1,p_2)+(p_2,p_3) + \cdots + (p_n,t)+h_s-h_t \]

所以 不管路径加的数都是 \(h_s-h_t\)

这就是 Johnson 了 那最后我们分析下时间复杂度吧

首先 SPFA 的时间复杂度是 \(\mathcal{O}(VE)\) Dijkstra 是 \(\mathcal{O}( (V+E) \log V)\)

所以 Johnson 的时间复杂度是 \(\mathcal{O}(VE)+\mathcal{O}( V (V+E) \log V)\) 就是 \(\mathcal{O}( V (V+E) \log V)\)

http://www.jsqmd.com/news/567236/

相关文章:

  • 低显存福音:ComfyUI+Nunchaku FLUX.1-dev量化版AI绘画快速体验
  • 申博机构筛选避坑清单|10 个细节,帮你避开所有套路(CSDN 独家)
  • Arduino I²C设备扫描库:复刻i2cdetect的嵌入式诊断工具
  • MiniCPM-o-4.5-nvidia-FlagOS跨平台部署:Windows系统配置要点
  • 成都装修公司哪家靠谱?2025-2026年度十大“预算包干”优选企业榜单发布 - 推荐官
  • 5大核心优势:开源下载工具重构云存储资源获取效率
  • 单片机存储系统:哈佛架构与ROM/RAM技术解析
  • 如何通过UltraVNC实现高效实用的远程桌面控制?
  • 别硬扛了!颈椎腰椎异常疼了 5 年,我才懂:省钱的康复路根本不是自己瞎扛
  • 1.5 Harness 架构深度解析:Claude Code 为什么强?
  • 酒店组网解决方案助力智能化提升客户体验
  • Qt6 + OpenGL 3.3 渲染环境搭建全指南:从空白窗口到专属渲染画布的优雅实现
  • hgproxy4.0.35.0之前版本数据库连接卡在parse状态
  • 大厂笔试面试八股文-算法-数组常考题-final
  • 自动驾驶控制:斯坦利(Stanley)算法C++纯代码实现
  • 瑞芯微(EASY EAI)RV1126B WIFI AP通讯
  • 基于Phi-3-mini-128k-instruct构建运维智能助手:Linux命令分析与故障排查
  • Tomcat中间件能够提供的能力
  • 从原理到实战:Java 数组核心知识与高阶用法
  • 无人机飞控参数调试:原理、流程与工程标准
  • 软件测试高频面试题 2026 最新整理(功能 + 自动化)
  • Phi-3-mini-4k-instruct-gguf参数详解:温度0.0时技术文档摘要的逻辑连贯性分析
  • 手把手教你用Scanpy搞定空间转录组分析:从Visium数据到FISH可视化(附避坑指南)
  • 三维空间RRT融合人工势场APF算法路径平滑处理
  • Python实战:从2024政府工作报告中智能提取关键数据短句
  • 高效掌握Markmap:让Markdown文本转换为交互式思维导图提升内容可视化效率的实战指南
  • pg_dump备份报错:Only syssso can access this table
  • 关于下一代程序员的“灵魂三问”:我们是在进化,还是在消失?
  • 华为 eNSP 实战:RIP 路由协议原理、应用场景与完整配置实验
  • 如何让单人游戏变身本地多人体验:Nucleus Co-Op的技术实现与应用