zoukankan      html  css  js  c++  java
  • 【模板】Johnson最短路_luoguP5905

    算法作用

    用来解决带负权的有向图的最短路问题。

    只要跑一次spfa,就可以随便跑Dij了。

    算法思想

    • 给每条边重新安排一个边权,使得不再存在负权边,并且可以由新图的最短路结果快速推出原图的最短路结果。

    • 不连通的对每个连通块可以分别求。所以我们只要考虑联通的情况下怎么做。

    • 那么,我们可以回想一下k短路,在哪个里面我们有最短路树。而且图中非树边我们给他们赋予了一个新的权值,意义是如果加上这条边,最短路会变大多少。我们发现,这个值一定是正的。

    • 然后,就很好玩了。你会发现这个东西,很裂项。因为他的表达式是(w_e+dis_{e_{from}}-dis_{e_{to}})

    • 于是,就发现,所有(i)(j)的路径,都是原来的路径长度再加上(dis_i-dis_j)

    • 赢了。

    代码

    luoguP5905

    #include<bits/stdc++.h>
    #define LL long long
    #define MAXN 3100
    #define MAXM 6100
    #define MAXNUM 10000000
    #define INF 1000000000
    using namespace std;
    template<typename T>void Read(T &cn)
    {
    	char c;int sig = 1;
    	while(!isdigit(c = getchar()))if(c == '-')sig = -1; cn = c-48;
    	while(isdigit(c = getchar()))cn = cn*10+c-48; cn*=sig;
    }
    template<typename T>void Write(T cn)
    {
    	if(cn < 0) {putchar('-'); cn = 0-cn; }
    	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
    	while(cn)cm = cm*10+cn%10,cn/=10,wei++;
    	while(wei--)putchar(cm%10+48),cm/=10;
    	putchar(cx+48);
    }
    struct qwe{
    	int a,b,ne,w;
    	void mk(int cn, int cm, int cx, int cw) {a = cn; b = cm; ne = cx; w = cw; }
    };
    struct qwer{
    	int a,b;
    	void mk(int cn, int cm) {a = cn; b = cm; }
    	inline friend bool operator <(qwer a, qwer b) {return a.b > b.b; }
    };
    qwe a[MAXM+MAXN+1];
    int alen;
    int head[MAXN+10];
    int n,m,p;
    int vis[MAXN+1], lu[MAXN+1], dui[MAXNUM+1], l, r;
    int ci[MAXN+1];
    int lu2[MAXN+1];
    qwer dui2[MAXM+MAXN+1];
    void lian(int cn, int cm, int cx) {a[++alen].mk(cn,cm,head[cn],cx); head[cn] = alen; }
    void spfa(int cn)
    {
    	l = r = 0;
    	memset(vis,0,sizeof(vis)); memset(ci,0,sizeof(ci));
    	dui[++r] = cn;
    	vis[0] = 1;
    	while(l < r)
    	{
    		int dang = dui[++l]; vis[dang] = 0;
    		ci[dang]++; if(ci[dang] > n) {p = 1; return; }
    		for(int i = head[dang];i;i = a[i].ne)
    		{
    			int y = a[i].b;
    			if(lu[y] <= lu[dang] + a[i].w) continue;
    			lu[y] = lu[dang] + a[i].w;
    			if(!vis[y]) dui[++r] = y, vis[y] = 1;
    		}
    	}
    }
    void dij(int cn, qwer dui[], int lu[])
    {
    	for(int i = 1;i<=n;i++) lu[i] = INF;
    	lu[cn] = 0; int dlen = 0; dui[++dlen].mk(cn,0);
    	while(dlen)
    	{
    		while(dlen && dui[1].b != lu[dui[1].a]) pop_heap(dui+1,dui+(dlen--)+1);
    		if(!dlen) break;
    		int dang = dui[1].a; pop_heap(dui+1,dui+(dlen--)+1);
    		for(int i = head[dang];i;i = a[i].ne)
    		{
    			int y = a[i].b;
    			if(lu[y] <= lu[dang] + a[i].w || !y) continue;
    			lu[y] = lu[dang] + a[i].w;
    			dui[++dlen].mk(y,lu[y]); push_heap(dui+1,dui+dlen+1);
    		}
    	}
    }
    int main()
    {
    	Read(n); Read(m);
    	alen = 0; memset(vis,0,sizeof(vis));
    	for(int i = 1;i<=m;i++) {int bx,by,bz; Read(bx); Read(by); Read(bz); lian(bx,by,bz); }
    	p = 0; for(int i = 1;i<=n;i++) lu[i] = INF;  
    	for(int i = 1;i<=n;i++) {if(lu[i] == INF) lu[i] = 0, spfa(i); if(p) {puts("-1"); return 0; } }
    	for(int i = 1;i<=m;i++) a[i].w += lu[a[i].a] - lu[a[i].b];
    	for(int i = 1;i<=n;i++)
    	{
    		dij(i,dui2,lu2);
    		LL ans = 0;
    		for(int j = 1;j<=n;j++) ans = ans + 1ll*j*(lu2[j] == INF ? INF : (lu2[j] - lu[i] + lu[j]));
    		Write(ans); puts("");
    	}
    	return 0;
    }
    
  • 相关阅读:
    xcode 查看stastic
    erlang 游戏服务器开发
    同一世界服务器架构--Erlang游戏服务器
    理解Erlang/OTP
    使用SecureCRT连接AWS的EC2
    redis单主机多实例
    Redis命令总结
    [redis] redis配置文件redis.conf的详细说明
    [转至云风的博客]开发笔记 (2) :redis 数据库结构设计
    Redis 集群方案
  • 原文地址:https://www.cnblogs.com/czyarl/p/12332827.html
Copyright © 2011-2022 走看看