【图论】Johnson算法

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

【图论】Johnson算法
适⽤于求解没有负环的全源最短路,最坏时间复杂度O(nm log m) ⽐Floyd要优秀(但是Floyd可以找出负环)。

在没有负权边时,使⽤n次单源最短路Dijkstra代替即可。

算法流程:
1、新建⼀个虚拟节点(编号为n+1),向[1,n]连接⼀条边权为0的虚拟边。

2、从n+1号节点开始跑⼀次队列优化BellmanFord,得到从n+1号虚拟节点到节点i的最短路hgt[i],假如存在负环,则⽆法求解。

3、删除虚拟节点和虚拟边(也可以直接选择忽视他们)
4、把每条⾮虚拟边(u,v,w)改为(u,v,w+hgt[u]-hgt[v])
5、对于每个点i属于[1,n],跑⼀次Dijkstra,得到从i节点到[1,n]的⾮虚拟节点的最短路dis[j]。

6、原本的[i,j]的最短路为dis[j]+hgt[i]-hgt[j]
最后把边权修改回来的操作可以省去。

namespace Johnson {
const int MAXN = 2e5 + 10;
int n;
vector<pil> G[MAXN];
ll hgt[MAXN];
ll dis[MAXN];
int cnt[MAXN];
bool vis[MAXN];
queue<int> Q;
priority_queue<pli> PQ;
bool bellmanford() {
fill(hgt + 1, hgt + 1 + n, LINF);
fill(cnt + 1, cnt + 1 + n, 0);
fill(vis + 1, vis + 1 + n, 0);
while(!Q.empty())
Q.pop();
hgt[n] = 0;
vis[n] = 1;
Q.push(n);
while(!Q.empty()) {
int u = Q.front();
Q.pop();
vis[u] = 0;
++cnt[u];
if(cnt[u] == n)
return false;
for(pil &p : G[u]) {
int v = p.first;
ll w = p.second;
if(hgt[v] <= hgt[u] + w)
continue;
hgt[v] = hgt[u] + w;
if(!vis[v]) {
vis[v] = 1;
Q.push(v);
}
}
}
return true;
}
void dijkstra(int s) {
fill(dis + 1, dis + 1 + n, LINF);
fill(vis + 1, vis + 1 + n, 0);
while(!PQ.empty())
PQ.pop();
dis[s] = 0;
PQ.push({-dis[s], s});
while(!PQ.empty()) {
int u = PQ.top().second;
PQ.pop();
if(vis[u])
continue;
vis[u] = 1;
for(pil &p : G[u]) {
int v = p.first;
ll w = p.second;
if(vis[v] || dis[v] <= dis[u] + w)
continue;
dis[v] = dis[u] + w;
PQ.push({-dis[v], v});
}
}
}
bool johnson() {
++n;
G[n].clear();
for(int i = 1; i <= n - 1; ++i)
G[n].eb(i, 0);
int res = bellmanford();
G[n].clear();
--n;
if(!res)
return false;
for(int u = 1; u <= n; ++u) {
for(pil &p : G[u]) {
int v = p.first;
p.second += hgt[u] - hgt[v]; }
}
for(int i = 1; i <= n; ++i) {
dijkstra(i);
for(int j = 1; j <= n; ++j) {
if(dis[j] != LINF)
dis[j] -= hgt[i] - hgt[j];
}
// do something
}
for(int u = 1; u <= n; ++u) {
for(pil &p : G[u]) {
int v = p.first;
p.second -= hgt[u] - hgt[v]; }
}
return true;
}
}Processing math: 100%。

相关文档
最新文档