zoukankan      html  css  js  c++  java
  • 网络流模板

    最简单的Ford-Fulkerson,复杂度O(FE) (F是最大流量,E是边数

    每次从源点到汇点dfs寻找增广路。

    const int MAXV = 2005;
    const int INF = 1<<30;
    struct Edge{ int to, cap, rev; };
    std::vector<Edge> G[MAXV];
    bool used[MAXV];
    
    void addedge(int from, int to, int cap) {
        G[from].push_back(Edge{to, cap, G[to].size()});
        G[to].push_back(Edge{from, 0, G[from].size()-1});
    }
    
    int dfs(int v, int t, int f) {
        if (v == t) return f;
        used[v] = true;
        for (int i = 0; i < G[v].size(); ++i) {
            Edge &e = G[v][i];
            if (!used[e.to] && e.cap > 0) {
                int d = dfs(e.to, t, std::min(f, e.cap));
                if (d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    
    int maxflow(int s, int t) {
        int flow = 0;
        for (; ;) {
            memset(used, 0, sizeof used);
            int f = dfs(s, t, INF);
            if (!f) return flow;
            flow += f;
        }
        return flow;
    }
    View Code

    把dfs换成bfs,就成了Edmonds-Karp

    代码多了一些,但是并不会快的样子。。

    #include <queue>
    #include <cstring>
    const int N = 2005;
    const int M = 2005;
    const int INF = 0x7fffffff;
    
    struct Edge {
        int from, to, next, cost;
    } edge[M];
    int head[N];
    int cnt_edge;
    void add_edge(int u, int v, int c)
    {
        edge[cnt_edge].to = v;
        edge[cnt_edge].from = u;
        edge[cnt_edge].cost = c;
        edge[cnt_edge].next = head[u];
        head[u] = cnt_edge++;
    }
    
    int pre[N], flow[N];
    std::queue<int> q;
    int bfs(int src, int des)
    {
        memset(pre, -1, sizeof pre);
        while (!q.empty()) q.pop();
        q.push(src);
        flow[src] = INF;
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            if (u == des) break;
            for (int i = head[u]; i != -1; i = edge[i].next)
            {
                int v = edge[i].to;
                int cost = edge[i].cost;
                if (pre[v] == -1 && cost > 0)
                {
                    flow[v] = std::min(flow[u], cost);
                    pre[v] = i; // 记录的是边
                    q.push(v);
                }
            }
        }
        if (pre[des] == -1) return -1;
        return flow[des];
    }
    
    int maxFlow(int src, int des)
    {
        int ans = 0;
        int in;
        while ((in = bfs(src, des)) != -1)
        {
            int k = des;
            while (k != src)
            {
                int last = pre[k];
                edge[last].cost -= in;
                edge[last ^ 1].cost += in;
                k = edge[last].from;
            }
            ans += in;
        }
        return ans;
    }
    
    int main()
    {
        int n, m;
        while (~scanf("%d%d", &m, &n))
        {
            int a, b, c;
            memset(head, -1, sizeof head);
            while (m--)
            {
                scanf("%d%d%d", &a, &b, &c);
                add_edge(a, b, c);
                add_edge(b, a, 0);
            }
            printf("%d
    ", maxFlow(1, n));
        }
    }
    View Code

    优化下,bfs构造分层图,然后每次都走最短的增广路,变成Dinic

    这样比上面快很多。。复杂度O(EV²) (E是边数,V是点数

    有了大概这个可以放弃上面的两个了。。

    据说比较适合有向无环图。。

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <queue>
    const int MAXV = 2005;
    const int INF = 1<<30;
    struct Edge{ int to, cap, rev; };
    std::vector<Edge> G[MAXV];
    int level[MAXV];
    int iter[MAXV]; //当前弧,之前的已经没有用了
    
    void addedge(int from, int to, int cap) {
        G[from].push_back(Edge{to, cap, G[to].size()});
        G[to].push_back(Edge{from, 0, G[from].size()-1});
    }
    
    void bfs(int s) {
        memset(level, -1, sizeof level);
        std::queue<int> que;
        level[s] = 0;
        que.push(s);
        while (!que.empty()) {
            int v = que.front(); que.pop();
            for (int i = 0; i < G[v].size(); ++i) {
                Edge &e = G[v][i];
                if (e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[v] + 1;
                    que.push(e.to);
                }
            }
        }
    }
    
    int dfs(int v, int t, int f) {
        if (v == t) return f;
        for (int &i = iter[v]; i < G[v].size(); ++i) { // 注意i是引用 实现当前弧优化
            Edge &e = G[v][i];
            if (e.cap > 0 && level[v] < level[e.to]) {
                int d = dfs(e.to, t, std::min(f, e.cap));
                if (d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    
    int maxflow(int s, int t) {
        int flow = 0;
        for (; ;) {
            bfs(s);
            if (level[t] < 0) return flow;
            memset(iter, 0, sizeof iter);
            int f;
            while ((f = dfs(s, t, INF)) > 0) {
                flow += f;
            }
        }
        return flow;
    }
    View Code

    SAP。。。并不是很懂。。。

    貌似没有比dinic快很多。。。

    const int N = 1000;
    const int M = 1000000;
    const int INF = 1 << 30;
    struct Edge {
        int from, to, next, w;//from一般用不到
    } edge[M];
    int head[N], cntE;
    int src, sink;
    int pre[N], cur[N], dis[N], gap[N];
    int que[N], open, tail;
    
    void addedge(int u, int v, int w) {
        edge[cntE].from = u;
        edge[cntE].to = v;
        edge[cntE].w = w;
        edge[cntE].next = head[u];
        head[u] = cntE++;
        edge[cntE].from = v;
        edge[cntE].to = u;
        edge[cntE].w = 0;
        edge[cntE].next = head[v];
        head[v] = cntE++;
    }
    void BFS() {
        int i, u, v;
        memset(gap, 0, sizeof(gap));
        memset(dis, -1, sizeof(dis));
        open = tail = 0;
        que[open] = sink;
        dis[sink] = 0;
        while (open <= tail) {
            u = que[open++];
            for (i = head[u]; ~i; i = edge[i].next) {
                v = edge[i].to;
                if (edge[i].w != 0 || dis[v] != -1) continue;
                que[++tail] = v;
                ++gap[dis[v] = dis[u] + 1];
            }
        }
    }
    int sap(int n) { //编号从1开始 1~n
        int i, v, u, flow = 0, aug = INF;
        int flag;
        BFS();
        gap[0] = 1;
        for (i = 1; i <= n; i++) cur[i] = head[i];
        u = pre[src] = src;
        while (dis[src] < n) {
            flag = 0;
            for (int j = cur[u]; ~j; j = edge[j].next) {
                v = edge[j].to;
                if (edge[j].w > 0 && dis[u] == dis[v] + 1) {
                    flag = 1;
                    if (edge[j].w < aug) aug = edge[j].w;
                    pre[v] = u; u = v;
                    if (u == sink) {
                        flow += aug;
                        while (u != src) {
                            u = pre[u];
                            edge[cur[u]].w -= aug;
                            edge[cur[u] ^ 1].w += aug;
                        }
                        aug = INF;
                    }
                    break;
                }
                cur[u] = edge[j].next;
            }
            if (flag) continue;
            int mindis = n;
            for (int j = head[u]; ~j; j = edge[j].next) {
                v = edge[j].to;
                if (edge[j].w > 0 && mindis > dis[v]) {
                    mindis = dis[v];
                    cur[u] = j;
                }
            }
            if (--gap[dis[u]] == 0) break;
            ++gap[dis[u] = mindis + 1];
            u = pre[u];
        }
        return flow;
    }
    
    int main() {
        memset(head, -1, sizeof head);
        cntE = 0;
    }
    View Code

     我决定选择dinic吧。。。好写。。。Orz。。

    最小费用最大流。。每次spfa找最短路增广。。

    好像挺慢的。。。

    #include <cstring>
    #include <cstdio>
    #include <queue>
    #define CLR(x, v, n) memset(x, v, sizeof(x[0])*n)
    using namespace std;
    const int N = 10000;
    const int M = 1000000;
    const int INF = 0x3f3f3f3f;
    
    struct Edge {
        int to, next, cap, flow, cost;
        void init(int _to, int _cap, int _cost, int _next) {
            to = _to; cap = _cap; cost = _cost; next = _next; flow = 0;
        }
    } edge[M];
    
    int head[N], cntE;
    int pre[N], dis[N];
    bool vis[N];
    int src, sink, tot;
    
    void dn(int &x, int y) { if(x>y) x=y; }
    
    void init() {
        cntE = 0;
        memset(head, -1, sizeof head);
    }
    
    void addedge(int u, int v, int cap, int cost) {
        edge[cntE].init(v, cap, cost, head[u]); head[u] = cntE++;
        edge[cntE].init(u, 0, -cost, head[v]); head[v] = cntE++;
    }
    
    bool spfa() {
        queue<int> q;
        fill(dis, dis+tot, INF); CLR(vis, false, tot); CLR(pre, -1, tot);
        dis[src] = 0; vis[src] = true;
        q.push(src);
        while (q.size()) {
            int u = q.front(); q.pop(); vis[u] = false;
            for (int i = head[u]; ~i; i = edge[i].next) {
                int v = edge[i].to;
                if (edge[i].cap > edge[i].flow && dis[u]+edge[i].cost < dis[v]) {
                    dis[v] = dis[u]+edge[i].cost;
                    pre[v] = i;
                    if (!vis[v]) {
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        if (pre[sink] == -1) return false;
        return true;
    }
    
    int MCMF(int &cost) {
        int flow = 0;
        cost = 0;
        while (spfa()) {
            int f = INF;
            for (int i = pre[sink]; ~i; i = pre[edge[i^1].to]) {
                dn(f, edge[i].cap - edge[i].flow);
            }
            for (int i = pre[sink]; ~i; i = pre[edge[i^1].to]) {
                edge[i].flow += f;
                edge[i^1].flow -= f;
                cost += edge[i].cost * f;
            }
            flow += f;
        }
        return flow;
    }
    View Code
  • 相关阅读:
    【★】IT界8大恐怖预言
    ★互联网告别免费时代,准备好了吗?
    ★互联网告别免费时代,准备好了吗?
    PS小实验-去除水印
    PS小实验-去除水印
    玩转PS路径,轻松画logo!
    玩转PS路径,轻松画logo!
    玩转PS路径,轻松画logo!
    地图收敛心得170405
    地图收敛心得170405
  • 原文地址:https://www.cnblogs.com/wenruo/p/5858418.html
Copyright © 2011-2022 走看看