学这个是为了支持在带负权值的图上跑 Dijkstra.

为了这个我们要考虑把负的权值搞正。

那么先把我们先人已经得到的结论摆出来。我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体就是在原图的基础上建立超级源点。

然后我们把得到的这个东西称为 势能 \(h\) ,我们对于原图的每条边 \((u,v)\)的边权加上 \(h_u-h_v\),然后就可以跑 Dijkstra 了,求出的答案是 \(dis_{i,j}-h_i+h_j\).然后我们证明这样搞是对的。

首先需要证明这个搞法不会使求出来的值变化。

对于一条 \(i\) 到 \(j\) 的最短路径,有经过的点集 \(S\) ,那么我们求出的最短路是:

\[dis_{i,j}=(w(S_1,S_2)+h_1-h_2)+(w(S_2,S_3)+h_2-h_3)+...+(w(S_{n-1},S_n)+h_{n-1}+h_n)
\]

然后我们不难发现前后两项有部分可以抵消,所以有(设 \(d_{i,j}\) 为直接 Dijkstra 跑出的答案):

\[dis_{i,j}=(w(S_1,S_2)+h_1-h_2)+(w(S_2,S_3)+h_2-h_3)+...+(w(S_{n-1},S_n)+h_{n-1}+h_n)
\]
\[=d_{i,j}+h_1+h_n
\]

在加上势能满足三角形不等式:\(w(u,v)+h_u \geqslant h_v\)

就是差分约束(和最短路)那个东西啦。然后变形得到所有修改后边权大于0.

就没啦(-)

Johnson 全源最短路

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
return s*f;
}
const ll INF=1e18;
const int N=3e3+3;
const int M=6e3+3;
int n,m;
struct Edge{
int v;ll w;
};
vector<int>head,nxt;
vector<Edge>to;
inline void join(int u,int v,int w){
nxt.push_back(head[u]);
head[u]=to.size();
to.push_back({v,w});
}
queue<int>q;
ll h[N];bool inq[N];
int hoop[N];
inline bool SPFA(int s){
while(!q.empty() ) q.pop();
for(int i=1;i<=n+1;++i){
h[i]=INF;inq[i]=0;hoop[i]=0;
}
inq[s]=1;q.push(s);h[s]=0;hoop[s]=1;
while(!q.empty() ){
int u=q.front();q.pop();inq[u]=0;
for(int i=head[u];~i;i=nxt[i]){
int v=to[i].v;ll w=to[i].w;
if(h[v]>h[u]+w){
h[v]=h[u]+w;
if(!inq[v]){
++hoop[v];
if(hoop[v]>n) return false;
q.push(v);
inq[v]=1;
}
}
}
}
return true;
}
ll dis[N][N];int S;
struct node{
int x;
inline friend bool operator <(node x,node y){
return dis[S][x.x]>dis[S][y.x];
}
};
namespace Dijkstra{
priority_queue<node>q;
inline void work(int s){
while(!q.empty() ) q.pop();
for(int i=1;i<=n;++i){
dis[s][i]=INF;
inq[i]=0;
}S=s;
inq[s]=1;q.push({s});dis[s][s]=0;
while(!q.empty() ){
int u=q.top().x;q.pop();inq[u]=0;
for(int i=head[u];~i;i=nxt[i]){
int v=to[i].v;ll w=to[i].w;
if(dis[s][v]>dis[s][u]+w){
dis[s][v]=dis[s][u]+w;
if(!inq[v]){
inq[v]=1;
q.push({v});
}
}
}
}
}
}
struct EDGE{
int u,v,w;
}e[M];
int main(){
//file(a);
n=read();m=read();
head.resize(n+1,-1);
for(int i=1;i<=m;++i){
int u=read(),v=read(),w=read();
join(u,v,w);
e[i]={u,v,w};
}
for(int i=1;i<=n;++i){
join(0,i,0);
}
if(!SPFA(0)) {printf("-1\n");return 0;}
head.clear();
head.resize(n+1,-1);
to.clear();nxt.clear();
for(int i=1;i<=m;++i){
join(e[i].u,e[i].v,e[i].w+h[e[i].u]-h[e[i].v]);
}
for(int i=1;i<=n;++i){
Dijkstra::work(i);
}
for(int i=1;i<=n;++i){
ll ans=0;
for(int j=1;j<=n;++j){
if(dis[i][j]==INF) ans+=1ll*(1e9)*j;
else ans+=1ll*(dis[i][j]-h[i]+h[j])*j;
}
printf("%lld\n",ans);
}
return 0;
}

Johnson 全源最短路的更多相关文章

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

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

  2. Johnson全源最短路

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

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

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  4. Johnson 全源最短路径算法

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

  5. 模板C++ 03图论算法 2最短路之全源最短路(Floyd)

    3.2最短路之全源最短路(Floyd) 这个算法用于求所有点对的最短距离.比调用n次SPFA的优点在于代码简单,时间复杂度为O(n^3).[无法计算含有负环的图] 依次扫描每一点(k),并以该点作为中 ...

  6. Johnson算法:多源最短路算法

    Johnson算法 请不要轻易点击标题 一个可以在有负边的图上使用的多源最短路算法 时间复杂度\(O(n \cdot m \cdot log \ m+n \cdot m)\) 空间复杂度\(O(n+m ...

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

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

  8. 【算法】单源最短路——Dijkstra

    对于固定起点的最短路算法,我们称之为单源最短路算法.单源最短路算法很多,最常见的就是dijkstra算法. dijkstra主要用的是一种贪心的思想,就是说如果i...s...t...j是最短路,那么 ...

  9. 图论:Floyd-多源最短路、无向图最小环

    在最短路问题中,如果我们面对的是稠密图(十分稠密的那种,比如说全连接图),计算多源最短路的时候,Floyd算法才能充分发挥它的优势,彻彻底底打败SPFA和Dijkstra 在别的最短路问题中都不推荐使 ...

随机推荐

  1. APICloud首款全功能集成开发工具重磅发布,彰显云端一体理念

    近日,APICloud重磅推出首款云端一体的全功能集成开发工具--APICloud Studio 2.为了更深入了解这款开发工具的特性及优势,APICloud CTO 邹达针对几个核心问题做出了解答. ...

  2. 微信小程序命名规则

    目录分析 src是主要的开发目录,各个文件实现功能如下所示: ├─.idea │ └─libraries ├─.temp ├─config └─src ├─assets │ └─images ├─co ...

  3. python---实现单例模式

    """ 单例模式 单利模式是一种设计模式, 应用该模式的类只会生成一个实例, 可以保证在程序的不同位置 都可以且仅可以取到同一个对象实例. 如果实例不存在, 会创建一个实 ...

  4. 第一阶段:Java基础之控制结构

    1.顺序结构 按照顺序控制结构运行,即语句从上到下,从左到右 2.选择结构 if..else..语句 switch..case..语句 3.循环结构 while循环 do...while & ...

  5. 在Vue3项目中使用pinia代替Vuex进行数据存储

    pinia是一个vue的状态存储库,你可以使用它来存储.共享一些跨组件或者页面的数据,使用起来和vuex非常类似.pina相对Vuex来说,更好的ts支持和代码自动补全功能.本篇随笔介绍pinia的基 ...

  6. React + TypeScript + Taro前端开发小结

    前言 项目到一段落,先来记录一下,本文以前端新手的角度记录React.TypeScript.Taro相关技术的开发体验以及遇到的问题和解决方法. 之前总说要学React(这篇博客:代码使我头疼之Rea ...

  7. Java语言学习day07--7月6日

    今日内容介绍1.流程控制语句switch2.数组 ###01switch语句解构​ * A:switch语句解构 * a:switch只能针对某个表达式的值作出判断,从而决定程序执行哪一段代码. * ...

  8. Android第十一、十二周作业

    图片一 用内部存储实现文件写入和读取功能 <?xml version="1.0" encoding="utf-8"?> <LinearLayo ...

  9. js 查找数组中某个字符出现的次数

    1. js 查找数组中某个字符出现的次数 代码示例 let arr = ['asd', 'green', 'yeadt', 'red', 'wati', 'red', 'red'] let index ...

  10. python基础练习题(题目 打印出所有的"水仙花数",所谓"水仙花数"是指一个三位数,其各位数字立方和等于该数本身)

    day8 --------------------------------------------------------------- 实例013:所有水仙花数 题目 打印出所有的"水仙花 ...