• 【图论】Dijkstra算法


    适用于非负权图,所有的边权都是非负数。
    或者从s节点出发的子图中,边权都是非负数的也可以。(从s出发没办法适用的,是负数甚至复数都无所谓。)

    Dijkstra算法

    标准版本,带有vis数组方便检查是否从s出发可以到达i。

    namespace Dijkstra {
    
        const int MAXN = 2e5 + 10;
    
        int n;
        vector<pii> G[MAXN];
    
        ll dis[MAXN];
        bool vis[MAXN];
    
        priority_queue<pli> PQ;
    
        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(pii &p : G[u]) {
                    int v = p.first;
                    int w = p.second;
                    if(vis[v] || dis[v] <= dis[u] + w)
                        continue;
                    dis[v] = dis[u] + w;
                    PQ.push({-dis[v], v});
                }
            }
        }
    
    }
    

    可能平均情况快一点的版本,拥有一个终点t,可以在非最坏情况下提前使得算法终止。由于算法提前终止所以除t以外的点不一定代表最终结果。

        ll dijkstra(int s, int t) {
            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;
                if(u == t)
                    break;
                for(pii &p : G[u]) {
                    int v = p.first;
                    int w = p.second;
                    if(vis[v] || dis[v] <= dis[u] + w)
                        continue;
                    dis[v] = dis[u] + w;
                    PQ.push({-dis[v], v});
                }
            }
            return dis[t];
        }
    

    计算从s出发到点i的最短路的条数

        void dijkstra(int s) {
            fill(dis + 1, dis + 1 + n, LINF);
            fill(cnt + 1, cnt + 1 + n, 0);
            fill(vis + 1, vis + 1 + n, 0);
            while(!PQ.empty())
                PQ.pop();
            dis[s] = 0;
            cnt[s] = 1;
            PQ.push({-dis[s], s});
            while(!PQ.empty()) {
                int u = PQ.top().second;
                PQ.pop();
                if(vis[u])
                    continue;
                vis[u] = 1;
                for(pii &p : G[u]) {
                    int v = p.first;
                    int w = p.second;
                    if(vis[v] || dis[v] < dis[u] + w)
                        continue;
                    if(dis[v] == dis[u] + w) {
                        cnt[v] += cnt[u];
                        continue;
                    }
                    dis[v] = dis[u] + w;
                    cnt[v] = cnt[u];
                    PQ.push({-dis[v], v});
                }
            }
        }
    

    把默认的优先队列修改为“待修改操作的堆”或者“线段树”可以把空间复杂度从 (O(n+m)) 降低到 (O(n)) ,但是看起来很花里胡哨。

  • 相关阅读:
    【BZOJ3626】【LNOI2014】—Lca(树链剖分)
    【BZOJ2434】【NOI2011】—阿狸的打字机(AC自动机+线段树)
    【UVA10498】—Happiness(线性规划/单纯形算法)
    【BZOJ4736】【清华集训2016】—温暖会指引我们前行(LCT)
    【BZOJ3451】【Tyvj1953】—Normal(点分治+NTT)
    【SCOI2019】—DAY2T1 湖之精灵的游戏(凸包+二分)
    【BZOJ4817】【SDOI2017】—树点涂色(LCT+树链剖分+线段树)
    【SCOI2019】—DAY2T1 RGB(容斥)
    Stargazer的分治讲义
    python datetime 模块
  • 原文地址:https://www.cnblogs.com/purinliang/p/14052183.html
Copyright © 2020-2023  润新知