【模板】图论算法模板(持更)

图论

图论是个大板块,建模在图论中占有很重要的地位,至于算法就是理解之后代码多敲敲,具体的架构还是差不多的。
图论大概有3个级别,第一级别就是没有边权的图,用于遍历或者强连通SCC跑一波等等;第二级别就是有边权的,这下算法多了,各种最短路和最小生成树都有了,一二级别有时候可以合并,遍历时没有边权实际上边权就是1;然后第三级别就是有流量(dalao们的网络流),当然还有各种变种,比如说加个费用啊什么的。

第一级别

SCC_Tarjan

struct Graph {
    struct edgetype {
        int to, next;
    };
    int n, dfs_clock, scc_cnt;
    std::vector< edgetype > edge;
    std::vector< int > head, dfn, low, scc;
    std::stack< int > Stack;
    Graph() : n(0), edge(0), head(0), dfn(0), low(0), scc(0) {}
    Graph(int n) : n(n), head(n + 1, -1), dfn(n + 1), low(n + 1), scc(n + 1) {}
    void AddEdge(int from, int to) {
        edge.push_back((edgetype){to, head[from]});
        head[from] = edge.size() - 1;
    }
    void DFS(int u) {
        dfn[u] = low[u] = ++dfs_clock;
        Stack.push(u);
        int v;
        for (int i = head[u]; i != -1; i = edge[i].next) {
            v = edge[i].to;
            if (!dfn[i]) {
                DFS(v);
                low[u] = min(low[u], dfn[v]);
            }
            else if (!scc[v])
                low[u] = min(low[u], low[v]);
        }
        if (low[u] == dfn[u]) {
            scc_cnt++;
            do {
                v = Stack.top();
                Stack.pop();
                scc[v] = scc_cnt;
            } while (u != v);
        }
    }
    int Get_SCC() {
        dfs_clock = scc_cnt = 0;
        while (!Stack.empty()) Stack.pop();
        for (int i = 1; i <= n; i++) 
            if (!dfn[i]) 
                DFS(i);
        return scc_cnt;
    }
};

第二级别

由于分块比较多,我直接按算法全部给出了。

SPFA

struct Graph {
    struct edgetype {
        int to, next, dist;
    };
    int n;
    std::vector< int > head;
    std::vector< long long > dist;
    std::vector< edgetype > edge;
    std::vector< bool > inQ;
    std::queue< int > Q;
    Graph() : n(0), head(0), dist(0), edge(0), inQ(0) {}
    Graph(int n, ) : n(n), head(n + 1, -1), dist(n + 1), inQ(n + 1) {}
    void AddEdge(int from, int to, int dist) {
        edge.push_back((edgetype){to, head[from], dist});
        head[from] = edge.size() - 1;
    }
    void SSSP(int s) {
        dist.assign(n + 1, 0x3f3f3f3f);
        inQ.assign(n + 1, false);
        while (!Q.empty()) Q.pop();
        Q.push(s); dist[s] = 0; inQ[s] = true;
        while (!Q.empty()) {
            int u = Q.front(); Q.pop(); inQ[u] = false;
            for (int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if (dist[v] > dist[u] + edge[i].dist) {
                    dist[v] = dist[u] + edge[i].dist;
                    if (!inQ[v]) {
                        Q.push(v);
                        inQ[v] = true;
                    }
                }
            }
        }
    }
    long long Distance(int s, int t) {
        SSSP(s);
        return dist[t];
    }
};

Dijkstra

struct Graph {
    struct EdgeType {
        int to, next, dist;
    };
    struct HeapNode {
        int point;
        long long dist;
        bool operator < (const HeapNode& rhs) const {
            return dist > rhs.dist;
        }
    };
    int n;
    std::vector< int > head;
    std::vector< long long >dist;
    std::vector< bool > done;
    std::vector< EdgeType > edge;
    std::priority_queue< HeapNode > Q; 
    Graph() : n(0), head(0), dist(0), done(0), edge(0) {}
    Graph(int n) : n(n), head(n + 1, -1), dist(n + 1), done(n + 1) {}
    void AddEdge(int from, int to, int dist) {
        edge.push_back((EdgeType){to, head[from], dist});       
        head[from] = edge.size() - 1;
    }
    void SSSP(int s) {
        dist.assign(n + 1, 0x3f3f3f3f);
        done.assign(n + 1, false);
        while (!Q.empty()) Q.pop();
        Q.push((HeapNode){s, 0}); dist[s] = 0;
        while (!Q.empty()) {
            HeapNode node = Q.top(); 
            Q.pop();
            if (done[node.point]) continue;
            int u = node.point;
            done[u] = true;
            for (int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if (dist[v] > dist[u] + edge[i].dist) {
                    dist[v] = dist[u] + edge[i].dist;
                    Q.push((HeapNode){v, dist[v]});
                }
            }
        }
    }
    long long Distance(int s, int t) {
        SSSP(s);
        return dist[t];
    }
};

Kruskal

struct Graph { 
    struct edgetype { 
        int from, to, dist; 
        bool operator < (const edgetype& rhs) const {
            return dist < rhs.dist;
        }
    };  
    int n;
    std::vector< edgetype > edge; 
    std::vector< int > f;
    Graph() : n(0), edge(0), f(0) {}  
    Graph(int n) : n(n), f(n + 1) {}
    void AddEdge(int from, int to, int dist) {  
        edge.push_back((edgetype){from, to, dist});  
    }  
    inline int FindRoot(int x) {
        return f[x] == x ? x : f[x] = FindRoot(f[x]);
    }
    long long MST() {
        int num = 0;
        long long ans = 0;
        for (int i = 1; i <= n; i++) f[i] = i;
        sort(edge.begin(), edge.end());
        for (unsigned int i = 0; i < edge.size(); i++) {
            int fu = FindRoot(edge[i].from);
            int fv = FindRoot(edge[i].to);
            if (fu != fv) {
                f[fu] = fv;
                ans += edge[i].dist;
                if (++num == n - 1) break;
            }
        }
        return ans;
    }
};  

Prim

struct Graph {
    struct edgetype {
        int to, next, dist;
    };
    struct heapnode {
        int point, dist;
        bool operator < (const heapnode& rhs) const {
            return dist > rhs.dist;
        }
    };
    int n;
    std::vector< int > head, dist;
    std::vector< edgetype > edge;
    std::priority_queue< heapnode > Q; 
    Graph() : n(0), head(0), dist(0), edge(0) {}
    Graph(int n) : n(n), head(n + 1, -1), dist(n + 1) {}
    inline void AddEdge(int from, int to, int dist) {
        edge.push_back((edgetype){to, head[from], dist});       
        head[from] = edge.size() - 1;
    }
    long long MST() {
        long long ans = 0;
        dist.assign(n + 1, 0x3f3f3f3f);
        while (!Q.empty()) Q.pop();
        Q.push((heapnode){1, 0});
        dist[1] = 0;
        while (!Q.empty()) {
            int u = Q.top().point;
            Q.pop();
            ans += dist[u];
            dist[u] = 0;
            for (int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if (dist[v] > edge[i].dist) {
                    dist[v] = edge[i].dist;
                    Q.push((heapnode){v, dist[v]});
                }
            }
        }
        return ans;
    }
};

Negative_Cycle

struct Graph {
    struct edgetype {
        int to, next, dist;
    };
    int n;
    std::vector< int > head, dist;
    std::vector< edgetype > edge;
    std::vector< bool > visit;
    Graph() : n(0), head(0), dist(0), edge(0), visit(0) {}
    Graph(int n) :n(n), head(n + 1, -1), dist(n + 1), visit(n + 1) {}
    void AddEdge(int from, int to, int dist) {
        edge.push_back((edgetype){to, head[from], dist});
        head[from] = edge.size() - 1;
    }
    void Negative_Cycle_Search(bool& exist, int u) {
        if (exist) return;
        visit[u] = true;
        for (int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if (dist[v] > dist[u] + edge[i].dist) {
                dist[v] = dist[u] + edge[i].dist;
                if (visit[v]) {
                    exist = true;
                    return;
                }
                Negative_Cycle_Search(exist, v);
            }
        }
        visit[u] = false;
    }
    bool Negative_Cycle() {
        dist.assign(n + 1, 0);
        visit.assign(n + 1, false);
        bool exist = false;
        for (int i = 1; i <= n && !exist; i++) 
            Negative_Cycle_Search(exist, i);
        return exist;
    }
};

第三级别

最大流

连续最短增广路(Dinic)

struct Graph {
    static const int infty = 0x7f7f7f7f;
    struct edgetype {
        int to, next, flow, cap;
    };
    int n, s, t;
    std::vector< edgetype > edge;
    std::vector< bool > visit;
    std::vector< int > head, d, cur;
    std::queue< int > Q;
    Graph() : n(0), edge(0), visit(0), head(0), d(0), cur(0) {}
    Graph(int n) : n(n), visit(n + 1), head(n + 1, -1), d(n + 1), cur(n + 1) {}
    void AddEdge(int from, int to, int cap) {
        edge.push_back((edgetype){to, head[from], 0, cap});
        head[from] = edge.size() - 1;
        edge.push_back((edgetype){from, head[to], 0, 0});
        head[to] = edge.size() - 1;
    }
    bool BFS() {
        visit.assign(n + 1, false);
        d.assign(n + 1, 0);
        while (!Q.empty()) Q.pop();
        Q.push(s); visit[s] = true;
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            for (int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if (!visit[v] && edge[i].flow < edge[i].cap) {
                    visit[v] = true;
                    d[v] = d[u] + 1;
                    Q.push(v);
                }
            }
        }
        return visit[t];
    }
    long long DFS(int u, int alpha) {
        if (u == t || alpha == 0) return alpha;
        long long flow = 0, f;
        for (int& i = cur[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if (d[u] + 1 == d[v] && (f = DFS(v, min(alpha, edge[i].cap - edge[i].flow))) > 0) {
                edge[i].flow += f; edge[i ^ 1].flow -= f; flow += f; alpha -= f;
                if (alpha == 0) break;
            }
        }
        return flow;
    }
    long long Maxflow(int s, int t) {
        this->s = s; this->t = t;
        long long maxflow = 0;
        while (BFS()) {
            cur.assign(head.begin(), head.end());
            maxflow += DFS(s, infty);
        }
        return maxflow;
    }
};

一般预流推进

struct Graph {
    static const int infty = 0x7f7f7f7f;
    struct edgetype {
        int to, next, flow, cap;
    };
    int n, s, t;
    std::vector< edgetype > edge;
    std::vector< int > head, h, excess;
    std::queue< int > Q;
    Graph() : n(0), edge(0), head(0), h(0), excess(0) {}
    Graph(int n) : n(n), head(n + 1, -1), h(n + 1), excess(n + 1) {}
    void AddEdge(int from, int to, int cap) {
        edge.push_back((edgetype){to, head[from], 0, cap});
        head[from] = edge.size() - 1;
        edge.push_back((edgetype){from, head[to], 0, 0});
        head[to] = edge.size() - 1;
    }
    void Push(int u, long long& maxflow) {
        for (int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            int f = min(edge[i].cap - edge[i].flow, excess[u]);
            if (f > 0 && (u == s || h[u] == h[v] + 1)) {
                edge[i].flow += f; edge[i ^ 1].flow -= f;
                excess[u] -= f; excess[v] += f;
                if (v == t) maxflow += f;
                else if (v != s) Q.push(v);
            }
        }
    }
    void Relabel(int u) {
        if (u != s && u != t && excess[u] > 0) h[u]++, Q.push(u); 
    }
    long long Maxflow(int s, int t) {
        this->s = s; this->t = t;
        long long maxflow = 0;
        excess.assign(n + 1, 0);
        h.assign(n + 1, 0); h[s] = n;
        excess[s] = infty; excess[t] = -infty;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front();
            Q.pop();
            Push(u, maxflow);
            Relabel(u);
        }
        return maxflow;
    }
};

最大标号预流推进

struct Graph {
    static const int infty = 0x7f7f7f7f;
    struct edgetype {
        int to, next, flow, cap;
    };
    struct node {
        int u, d;
        bool operator < (const node& rhs) const {
            return d < rhs.d;
        }
    };
    int n, s, t;
    std::vector< edgetype > edge;
    std::vector< int > head, h, excess;
    std::priority_queue< node > Q;
    Graph() : n(0), edge(0), head(0), h(0), excess(0) {}
    Graph(int n) : n(n), head(n + 1, -1), h(n + 1), excess(n + 1) {}
    void AddEdge(int from, int to, int cap) {
        edge.push_back((edgetype){to, head[from], 0, cap});
        head[from] = edge.size() - 1;
        edge.push_back((edgetype){from, head[to], 0, 0});
        head[to] = edge.size() - 1;
    }
    void Push(int u, long long& maxflow) {
        for (int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            int f = min(edge[i].cap - edge[i].flow, excess[u]);
            if (f > 0 && (u == s || h[u] == h[v] + 1)) {
                edge[i].flow += f; edge[i ^ 1].flow -= f;
                excess[u] -= f; excess[v] += f;
                if (v == t) maxflow += f;
                else if (v != s) Q.push((node){v, h[v]});
            }
        }
    }
    void Relabel(int u) {
        if (u != s && u != t && excess[u] > 0) h[u]++, Q.push((node){u, h[u]}); 
    }
    long long Maxflow(int s, int t) {
        this->s = s; this->t = t;
        long long maxflow = 0;
        excess.assign(n + 1, 0);
        h.assign(n + 1, 0); h[s] = n;
        excess[s] = infty; excess[t] = -infty;
        Q.push((node){s, n});
        while (!Q.empty()) {
            int u = Q.top().u;
            Q.pop();
            Push(u, maxflow);
            Relabel(u);
        }
        return maxflow;
    }
};

最小费用最大流

struct Graph {
    static const int infty = 0x7f7f7f7f;
    struct edgetype {
        int to, next, flow, cap, cost;
    };
    int n, s, t;
    std::vector< edgetype > edge;
    std::vector< bool > inQ;
    std::vector< int > head, dist, path;
    std::queue< int > Q;
    Graph() : n(0), edge(0), inQ(0), head(0), dist(0), path(0) {}
    Graph(int n) : n(n), inQ(n + 1), head(n + 1, -1), dist(n + 1), path(n + 1) {}
    void AddEdge(int from, int to, int cap, int cost) {
        edge.push_back((edgetype){to, head[from], 0, cap, cost});
        head[from] = edge.size() - 1;
        edge.push_back((edgetype){from, head[to], 0, 0, -cost});
        head[to] = edge.size() - 1;
    }
    bool FindPath() {
        dist.assign(n + 1, infty);
        inQ.assign(n + 1, false);
        path.assign(n + 1, -1);
        while (!Q.empty()) Q.pop();
        Q.push(s); dist[s] = 0; inQ[s] = true; 
        while (!Q.empty()) {
            int u = Q.front(); Q.pop(); inQ[u] = false;
            for (int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if (edge[i].flow < edge[i].cap && dist[v] > dist[u] + edge[i].cost) {
                    dist[v] = dist[u] + edge[i].cost; path[v] = i; 
                    if (!inQ[v]) {
                        Q.push(v);
                        inQ[v] = true;
                    }
                }
            }
        }
        return path[t] != -1;
    }
    void Argument(long long& Maxflow, long long& Mincost) {
        long long alpha = infty;
        for (int i = path[t]; i != -1; i = path[edge[i ^ 1].to]) 
            alpha = min(alpha, edge[i].cap - edge[i].flow);
        Maxflow += alpha; Mincost += dist[t] * alpha;
        for (int i = path[t]; i != -1; i = path[edge[i ^ 1].to]) {
            edge[i].flow += alpha;
            edge[i ^ 1].flow -= alpha;
        }
    }
    std::pair< long long, long long > MincostMaxflow(int s, int t) {
        this->s = s; this->t = t;
        long long Maxflow = 0, Mincost = 0;
        while (FindPath())
            Argument(Maxflow, Mincost);
        return std::make_pair(Maxflow, Mincost);
    }
};

这也要慢慢来,,,总结总是需要时间的

猜你喜欢

转载自blog.csdn.net/diogenes_/article/details/79969566
今日推荐