【】2024.3.24

2024.3.24 【最后死去的人,是最不幸的。】

Sunday 二月十五


P5905 【模板】全源最短路(Johnson)
//2024.3.24
//by white_ice
#include<bits/stdc++.h>
using namespace std;
#define itn int
const int oo = 5003;
const int inf = 1e9;

struct nod{int v,w,nxt;}st[oo<<1];
int head[oo],top;
void add(int x,itn y,int w){
    top++;
    st[top].w = w;
    st[top].v = y;
    st[top].nxt = head[x];
    head[x] = top;
}

struct node{
    int dis,id;
    bool operator<(const node &a)const {return dis>a.dis;}
    node(itn d,itn x){dis=d,id = x;}
};

itn n,m;

itn h[oo],t[oo];
bool vis[oo];
bool spfa(int s) {
    queue<int> q;
    memset(h, 63, sizeof(h));
    h[s] = 0, vis[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i=head[u];i;i=st[i].nxt){
            int v = st[i].v;
            if (h[v]>h[u]+st[i].w) {
                h[v]=h[u]+st[i].w;
                if (!vis[v]) {
                    vis[v] = 1;
                    q.push(v);
                    t[v]++;
                    if (t[v] == n+1)
                        return false;
                }
            }
        }
    }
    return true;
}
itn dis[oo];
void dijkstra(int s){
    priority_queue<node> q;
    for (int i=1;i<=n;i++)
        dis[i] = inf;
    memset(vis, 0, sizeof(vis));
    dis[s] = 0;
    q.push(node(0, s));
    while (!q.empty()) {
        int u = q.top().id;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = 1;
        for (int i=head[u];i;i=st[i].nxt) {
            int v = st[i].v;
                if (dis[v]>dis[u]+st[i].w) {
                    dis[v]=dis[u]+st[i].w;
                    if (!vis[v])
                        q.push(node(dis[v], v));
                }
        }
    }
    return;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);

    cin >> n >> m;
    for (int i=1;i<=m;i++){
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
    }
    for (int i=1;i<=n;i++)
        add(0, i, 0);

    if (!spfa(0)){
        cout << -1 ;
        return 0;
    }

    for (int u=1;u<=n;u++)
        for (int i=head[u];i;i=st[i].nxt)
            st[i].w+=h[u]-h[st[i].v];

    for (int i=1;i<=n;i++){
        dijkstra(i);
        long long ans = 0;
        for (int j = 1; j <= n; j++) {
            if (dis[j] == inf)
                ans += j * inf;
            else ans += j * (dis[j] + h[j] - h[i]);
    }
    cout << ans << endl;
  }
  return 0;
}

全源最短路(Johnson)

我是oiwiki链接

Johnson 和 Floyd 一样,是一种能求出无负环图上任意两点间最短路径的算法。该算法在 1977 年由 Donald B. Johnson 提出。

任意两点间的最短路可以通过枚举起点,跑 n 次 Bellman–Ford 算法解决,时间复杂度是 O(n^2m) 的,也可以直接用 Floyd 算法解决,时间复杂度为 O(n^3)。

注意到堆优化的 Dijkstra 算法求单源最短路径的时间复杂度比 Bellman–Ford 更优,如果枚举起点,跑 n 次 Dijkstra 算法,就可以在 O(nm\log m)(取决于 Dijkstra 算法的实现)的时间复杂度内解决本问题,比上述跑 n 次 Bellman–Ford 算法的时间复杂度更优秀,在稀疏图上也比 Floyd 算法的时间复杂度更加优秀。

但 Dijkstra 算法不能正确求解带负权边的最短路,因此我们需要对原图上的边进行预处理,确保所有边的边权均非负。

一种容易想到的方法是给所有边的边权同时加上一个正数 x,从而让所有边的边权均非负。如果新图上起点到终点的最短路经过了 k 条边,则将最短路减去 kx 即可得到实际最短路。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值