ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Johnson 全源最短路

2021-10-01 14:00:28  阅读:180  来源: 互联网

标签:cnt Johnson int 全源 vis mapp 短路 dis


Johnson 全源最短路

Johnson 和 Floyd 一样,是一种能求出无负环图上任意两点间最短路径的算法。该算法在 1977 年由 Donald B. Johnson 提出。
Johnson 算法则通过另外一种方法来给每条边重新标注边权。
我们新建一个虚拟节点(在这里我们就设它的编号为0)。从这个点向其他所有点连一条边权为0的边。
接下来用SPFA算法求出从0号点到其他所有点的最短路,记为 dis
假如存在一条从点u到点v,边权为w的边,则我们将该边的边权重新设置为w += dis[u] - dis[v];
接下来以每个点为起点,跑 n轮 Dijkstra 算法即可求出任意两点间的最短路了。
最后加上dis[v] - dis[u];
容易看出,该算法的时间复杂度是O(nmlogm) 。

luogu P5905 Johnson 全源最短路

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#define INF 1000000000ll
using namespace std;
typedef long long ll;
const int N=2e4;
struct  edge{
    int from;
    int to;
    int dis;
    int next;
}e[N];
int head[N],cnt;
int n,m,u,v,w;
void add(int u,int v,int w)
{
     ++cnt;
     e[cnt].from = u;
     e[cnt].to = v;
     e[cnt].dis = w;
     e[cnt].next = head[u];
     head[u] = cnt;
}
int mapp[N];
int d[N];
int num[N];
bool vis[N];
queue<int> q;
bool SPFA(int u)
{
    memset(mapp,0x3f,sizeof(mapp));
    memset(vis,0,sizeof(vis));
    mapp[u] = 0; vis[u] = true;
    q.push(u);
    while(!q.empty())
    {
       int x = q.front();
       vis[x] = false;
       q.pop();
       for(int i=head[x];i;i=e[i].next)
       {
           int y = e[i].to;
           if(mapp[y] > mapp[x] + e[i].dis)
           {
               mapp[y] = mapp[x] + e[i].dis;
               if(vis[y] == false)
               {
                  vis[y] = true;
                  num[y]++;
                  q.push(y);
               }
               if(num[y] >= n + 1) return true;
           }
       }
    }
    return false;
}
struct node{
    int dis;
    int pos;
    bool operator <(const node &x)const
    {
        return x.dis < dis;
    }
};
priority_queue<node> Q;
void Dijkstra(int u)
{
     memset(d,0x3f,sizeof(d));
     memset(vis,0,sizeof(vis));
     d[u] = 0;
     Q.push((node){0,u});
     while(!Q.empty())
     {
         node p = Q.top();
         Q.pop();
         int x = p.pos;
         if(vis[x]) continue;
         vis[x] = 1;
         for(int i=head[x];i;i=e[i].next)
         {
             int y = e[i].to;
             if(d[y] > d[x] + e[i].dis)
             {
                d[y] = d[x] + e[i].dis;
                Q.push((node){d[y],y});
             }
         }
     }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    for(int i=1;i<=n;i++)
    add(n+1,i,0);
    bool flag = SPFA(n+1);
    if(flag == true) 
    {
        puts("-1");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=e[j].next)
        e[j].dis += mapp[i] - mapp[e[j].to];
    }
    for(int i=1;i<=n;i++)
    {
        Dijkstra(i);
        ll sum = 0;
        for(int j=1;j<=n;j++)
        {
            if(d[j] == 1061109567) 
            {
                sum += (ll)j*INF;
            }
            else sum += (ll)j*(d[j] + mapp[j] - mapp[i]);
            
        }
        printf("%lld\n",sum);
    }
    return 0;
}

标签:cnt,Johnson,int,全源,vis,mapp,短路,dis
来源: https://www.cnblogs.com/Elgina/p/15359297.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有