Johnson 全源最短路径算法学习笔记

如果你希望得到带互动的极简文字体验,请点这里

我们来学习johnson

Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法。它允许一些边权重为负数,但可能不存在负权重循环。它的工作原理是使用Bellman-Ford 算法来计算输入图的转换,该转换去除了所有负权重,从而允许在转换后的图上使用Dijkstra 算法。Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法。它允许一些边权重为负数,但可能不存在负权重循环。它的工作原理是使用Bellman-Ford 算法来计算输入图的转换,该转换去除了所有负权重,从而允许在转换后的图上使用Dijkstra 算法。

--维基百科

  • 可以发现排序算法中最能够全源的只有Johnson 和 Floyd

最优情况:

全源最短路跑\(n\) 次 Bellman-Ford 算法解决,时间复杂度是\(O(n^2m)\),原始是Floyd的\(O(n^3)\)

我们可以更优,使用迪杰斯特拉\(O(nm \space logm)\)

但是我们还关注能否处理负边

所以只有SPFA,Floyd,贝尔曼,Johnson可以解决

原理解释

所以我们解决带负边的全源最短路时同时兼顾时间应该怎么做?

  • 使用Dijkstra

    但是Dijkstra不能处理有负边的问题,所以我们可以使边变为正数,我们基本得到3个猜想:
  1. 对每条边进行相同的增量,使所有边非负。
  2. 改变图的结构,不改变图的性质,使Dijkstra可做。
  3. 对每条边单独设计增量,使图的性质保证并且全图非负。

可以看出只有第三种是正确的。

为什么第一种不正确?

如上图(箭头错,1->3应该是3->1)3->2的最短路原本是-2(走上面),但是对于边权+5的图(绿)就成了9(走下面),路径发生了改变,不可取。

Johnson算法核心

建一个超级源,到所有点连0 权边,对超级源跑一遍SPFA,求出每个点的dis 值。重构原图边权,对于边 , , ,将其边权修改为 + dis − dis 。

由三角不等式: + dis ≥ dis ,从而新的边权一定是非负数。

在新图上跑全源 Dijkstra,以 \(u_0\) 为起点,假设经过 \(u_1\), \(u_2\), … , \(u_{t-1}\) 到达 \(u_t\) 。

则经过的边权分别为 $w_{12} $ \(-dis u_2 + w_{2,3}\) $ + dis u_2 − dis u_3 + ⋯ + $ $w_{t−1},t + dis u_{t−1} -dis u_t $

\[= w_{1,2} + w_{2,3} + ⋯ + w _{t−1,t} + (dis u_1 − dis u_t )
\]

只需将跑出的最短路结果做 \(− (dis u_1 − dis u_t )\) 变换就可以得到真实最短路。

正确性

为什么我们使用这个方法是正确的

在重新加权的图中,节点对s和t之间的所有路径都添加了相同的数量\(h ( s ) - h ( t )\)。

正确当且仅当重新加权后的最短路径是原始的最短路径。

\(dis_v \ge dis_u+e_w\)因此,不可能有负边:如果边 \(u \to v\) 在重新加权后具有负权重,那么从 \(q \to u\) 的零长度路径与这条边将形成从 \(q \to v\) 的负长度路径,这与以下事实相矛盾所有顶点到 \(q\) 的距离为零。

负边的不存在确保了 Dijkstra 算法找到的路径的最优性。

原始图中的距离可以通过逆重加权变换从重加权图中的Dijkstra算法计算出的距离计算出来。

Johnson 算法的前三个阶段如下图所示

图中左侧的图形有两个负边,但没有负循环。

中心图显示了新的顶点 \(q\) ,一个最短路径树,由 Bellman-Ford 算法计算,\(q\) 作为起始顶点,每个其他节点计算的值 \(h ( v )\) 作为从 \(q\) 到该节点的最短路径的长度节点。

请注意,这些值都是非正数,因为q到每个顶点都有一条长度为零的边,并且最短路径不能长于该边。

右侧显示了重新加权的图,通过替换每个边的权重形成 \({\displaystyle w(u,v)}{\displaystyle w(u,v)}\) 由 \(w ( u , v ) + h ( u ) − h ( v )\)。

在这个重新加权的图中,所有边的权重都是非负的,但任意两个节点之间的最短路径使用与原始图中相同两个节点之间的最短路径相同的边序列。该算法最后将 Dijkstra 算法应用于重新加权图中的四个起始节点中的每一个。

#include<bits/stdc++.h>
#define ll long long
#define fd(i, a, b) for (ll i = a; i >= b; i--)
#define r(i, a) for (ll i = fir[a]; i; i = e[i].nex)
#define file(a) freopen(#a ".in", "r", stdin);
#define il inline
#define gc getchar()
#define f(i,a,b) for(ll i=a;i<=b;i++)
using namespace std;
const ll maxn=3e5+10,INF=1e16;
il ll read(){
ll x=0,f=1;char ch=gc;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc;}
while(ch>='0'&&ch<='9') x=(x*10)+(ch^48),ch=gc;
return x*f;
}
ll fir[maxn],n,m,cnt;
struct edge{ll to,nex,w;}e[maxn<<1];
il void add(ll a,ll b,ll c){e[++cnt].to=b,e[cnt].w=c,e[cnt].nex=fir[a];fir[a]=cnt;}
bool vis[maxn];
ll far[maxn];
ll num[maxn];
il bool spfa(ll x){
queue<ll> q;
memset(far,0x7f,sizeof(far));
far[x]=0;
q.push(x);
while(!q.empty()){
ll u=q.front();
// cout<<far[u]<<endl;
// cout<<u<<endl;
vis[u]=0;
if(++num[u]>n) return 0;
q.pop();
r(i,u){
ll v=e[i].to;
// cout<<e[i].w<<endl;
if(far[v]>far[u]+e[i].w){
far[v]=far[u]+e[i].w;
// cout<<far[v]<<endl;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return 1;
}
priority_queue<pair<ll,ll> >q;
ll dis[maxn],cop;
il void dijkstra(ll x){
memset(dis,0x7f,sizeof(dis));
memset(vis,0,sizeof(vis));
cop=dis[0];
dis[x]=0;
q.push(make_pair(0,x));
while(!q.empty()){
ll u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
r(i,u){
ll v=e[i].to;
// cout<<e[i].w<<endl;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
q.push(make_pair(-dis[v],v));
}
}
}
}
ll Add=1e9;
int main()
{
n=read(),m=read();
f(i,1,m){
ll x=read(),y=read(),z=read();
add(x,y,z);
}
f(i,1,n) add(0,i,0);
// cout<<1;
if(spfa(0)){
f(i,1,n) r(j,i){
// cout<<far[i]-far[e[j].to]<<endl;
e[j].w+=far[i]-far[e[j].to];
// cout<<e[j].w<<endl;
}
// f(i,1,n) cout<<far[i]<<" ";
// cout<<endl;
f(i,1,n){
ll ans=0;
dijkstra(i);
f(j,1,n){
if(dis[j]==cop) ans+=j*Add;
else ans+=j*(dis[j]+far[j]-far[i]);
}
printf("%lld\n",ans);
}
}
else printf("-1");
}

参考文献

1.Johnson's algorithm--wikipedia

Johnson 全源最短路径算法学习笔记的更多相关文章

  1. Johnson 全源最短路径算法

    解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...

  2. Floyd-Warshall 全源最短路径算法

    Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E) 上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths Probl ...

  3. 【学习笔记】 Johnson 全源最短路

    前置扯淡 一年多前学的最短路,当时就会了几个名词的拼写,啥也没想过 几个月之前,听说了"全源最短路"这个东西,当时也没说学一下,现在补一下(感觉实在是没啥用) 介绍 由于\(spf ...

  4. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  5. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  6. Johnson全源最短路

    例题:P5905 [模板]Johnson 全源最短路 首先考虑求全源最短路的几种方法: Floyd:时间复杂度\(O(n^3)\),可以处理负权边,但不能处理负环,而且速度很慢. Bellman-Fo ...

  7. Johnson 全源最短路

    学这个是为了支持在带负权值的图上跑 Dijkstra. 为了这个我们要考虑把负的权值搞正. 那么先把我们先人已经得到的结论摆出来.我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体 ...

  8. Dijkstra 单源最短路径算法

    Dijkstra 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法,由计算机科学家 Edsger Dijkstra 于 1956 年 ...

  9. Bellman-Ford 单源最短路径算法

    Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 Richard Bellman 和 Leste ...

随机推荐

  1. Python3-sqlalchemy-orm 创建关联表带外键并插入数据

    #-*-coding:utf-8-*- #__author__ = "logan.xu" import sqlalchemy from sqlalchemy import crea ...

  2. Kafka详细教程加面试题

    一.部署kafka集群 启动zookeeper服务: zkServer.sh start 修改配置文件config/server.properties #broker 的全局唯一编号,不能重复 bro ...

  3. Appium自动化(11) - 详解 Applications 类里的方法和源码解析

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 Applications 类 ...

  4. KMP算法中的几个疑问

    KMP算法next数组求解实现 首先我们通过应用场景将KMP算法中用到的名词做一个说明: 在一个字符串(string1)中查询是否存在另一个字符串(string2). 在字符串匹配算法中,我们通常将字 ...

  5. SprinBoot-SpringData-整合

    目录 SpringData 整合JDBC JDBCTemplate 整合Druid 配置数据源 配置Druid数据源监控 整合MyBatis 整合测试 整合Redis 测试整合 序列化配置 自定义re ...

  6. 隐私安全设置:NET:ERR_CERT_AUTHORITY_INVALID message in Chrome.

    背景 访问一个内部网站时,遇到下面的问题,导致网站不能打开:NET:ERR_CERT_AUTHORITY_INVALID message in Chrome.从错误信息来看,这是由于网站的证书问题导致 ...

  7. 网站URL如何SEO优化

    前言 本文讲解网站的URL如何进行SEO优化,并在自己的WordPress博客echeverra中优化URL. 起因 对于SEO我了解的并不多,只知道SEO做的好,那么各大搜索网站搜索你网站相关内容时 ...

  8. Django学习day02随堂笔记

    每日测验 """ 今日考题 1.谈谈你对web框架的认识,简述web框架请求流程 2.python三大主流web框架的区别 3.安装django需要注意的事项有哪些(最少 ...

  9. TP5数据库数据变动日志记录设计

    根据网友的设计进行了部分调整: 用户分为管理员admin表和用户user表 记录操作表数据 增删改: insert/delete/update <?php /** * OperateLog.ph ...

  10. 数据库删除discuz 部分数据操作

    如何快速清理discuz 3.2 中等待审核的回复数:pre_forum_post_moderate,点击清空 清空回收站的主题帖:DELETE FROM `pre_forum_thread` WHE ...