Johnson 全源最短路
学这个是为了支持在带负权值的图上跑 Dijkstra.
为了这个我们要考虑把负的权值搞正。
那么先把我们先人已经得到的结论摆出来。我们考虑先用 SPFA 对着一个满足三角形不等式的图跑一次最短路,具体就是在原图的基础上建立超级源点。
然后我们把得到的这个东西称为 势能 \(h\) ,我们对于原图的每条边 \((u,v)\)的边权加上 \(h_u-h_v\),然后就可以跑 Dijkstra 了,求出的答案是 \(dis_{i,j}-h_i+h_j\).然后我们证明这样搞是对的。
首先需要证明这个搞法不会使求出来的值变化。
对于一条 \(i\) 到 \(j\) 的最短路径,有经过的点集 \(S\) ,那么我们求出的最短路是:
\]
然后我们不难发现前后两项有部分可以抵消,所以有(设 \(d_{i,j}\) 为直接 Dijkstra 跑出的答案):
\]
\]
在加上势能满足三角形不等式:\(w(u,v)+h_u \geqslant h_v\)
就是差分约束(和最短路)那个东西啦。然后变形得到所有修改后边权大于0.
就没啦(-)
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 全源最短路的更多相关文章
- 【学习笔记】 Johnson 全源最短路
前置扯淡 一年多前学的最短路,当时就会了几个名词的拼写,啥也没想过 几个月之前,听说了"全源最短路"这个东西,当时也没说学一下,现在补一下(感觉实在是没啥用) 介绍 由于\(spf ...
- Johnson全源最短路
例题:P5905 [模板]Johnson 全源最短路 首先考虑求全源最短路的几种方法: Floyd:时间复杂度\(O(n^3)\),可以处理负权边,但不能处理负环,而且速度很慢. Bellman-Fo ...
- Johnson 全源最短路径算法学习笔记
Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...
- Johnson 全源最短路径算法
解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...
- 模板C++ 03图论算法 2最短路之全源最短路(Floyd)
3.2最短路之全源最短路(Floyd) 这个算法用于求所有点对的最短距离.比调用n次SPFA的优点在于代码简单,时间复杂度为O(n^3).[无法计算含有负环的图] 依次扫描每一点(k),并以该点作为中 ...
- Johnson算法:多源最短路算法
Johnson算法 请不要轻易点击标题 一个可以在有负边的图上使用的多源最短路算法 时间复杂度\(O(n \cdot m \cdot log \ m+n \cdot m)\) 空间复杂度\(O(n+m ...
- Floyd-Warshall 全源最短路径算法
Floyd-Warshall 算法采用动态规划方案来解决在一个有向图 G = (V, E) 上每对顶点间的最短路径问题,即全源最短路径问题(All-Pairs Shortest Paths Probl ...
- 【算法】单源最短路——Dijkstra
对于固定起点的最短路算法,我们称之为单源最短路算法.单源最短路算法很多,最常见的就是dijkstra算法. dijkstra主要用的是一种贪心的思想,就是说如果i...s...t...j是最短路,那么 ...
- 图论:Floyd-多源最短路、无向图最小环
在最短路问题中,如果我们面对的是稠密图(十分稠密的那种,比如说全连接图),计算多源最短路的时候,Floyd算法才能充分发挥它的优势,彻彻底底打败SPFA和Dijkstra 在别的最短路问题中都不推荐使 ...
随机推荐
- h5 在全屏iphonex中的适配
iphonex 已经上线有一段时间了,作为业界刘海屏幕第一款机型,导致全屏不能正常的全屏显示了,,所以需要对iphonx 适配,下面就详细说说如何适配 先看一张适配前后的图: iphonex 提供的 ...
- css实现半圆效果
效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- DOCTYPE(⽂档类型) 的作⽤
DOCTYPE是HTML5中一种标准通用标记语言的文档类型声明,它的目的是告诉浏览器(解析器)应该以什么样(html或xhtml)的文档类型定义来解析文档,不同的渲染模式会影响浏览器对 CSS 代码甚 ...
- LC-1
Two Sum Given an array of integers nums and an integer target, return indices of the two numbers suc ...
- 约定编程与Sping AOP
一.约定编程 Spring AOP是一种约定流程的编程,咱们可以先通过动态代理模式的实现来理解Spring AOP的概念. 代理的逻辑很简单,例如,当你需要采访一名儿童时,首先需要经过他父母的同意,在 ...
- 2021.12.08 平衡树——FHQ Treap
2021.12.08 平衡树--FHQ Treap http://www.yhzq-blog.cc/fhqtreapzongjie/ https://www.cnblogs.com/zwfymqz/p ...
- JVM内存管理面试常见问题全解
目录 一.什么是JVM 1.jvm的三个组成部分 二.类加载系统 1.类的加载过程 2.类加载器 三.双亲委派机制 1.双亲委派机制介绍 2.为什么要双亲委派机制 3.双亲委派机制的核心源码 4.全盘 ...
- k8s入门之基础环境准备(一)
一.在虚拟机中安装Ubuntu20.04.4系统 1.下载Ubuntu20.04.4服务器版本系统 下载链接地址如下: https://mirrors.tuna.tsinghua.edu.cn/ubu ...
- Apache Doris Oracle ODBC外表使用指南
1.软件环境 操作系统:ubuntu 18.04 Apache Doris :0.15 Postgresql数据库:oracle 19c UnixODBC:2.3.4 Oracle ODBC :ins ...
- 使用aspnetcore前后端分离开发,你一定要知道这个
前言 用过Vue单页面应用开发的,一定都知道Vue-router这个路由组件,它支持hash和history两种模式. HTML5 History 模式 vue-router 默认 hash 模式 - ...