• 最大流相关算法实现


    1 增广路算法处理最大流问题

    struct Edge {
        int from;//起点 
        int to;//终点
        int cap;//容量 
        int flow;//流量
        Edge(int u, int v, int c, int f):form(u), to(v), cap(c), flow(f) {}
    };
    
    struct EdomonsKarp {
        int n, m;
        vector<Edge> edges;//边数的两倍,正向+反向
        vector<int> G[maxn];//邻接表,G[i][j]表示节点i的第j条边在e数组中的序号
        int a[maxn];//起点到i的可改进量(残量)
        int p[maxn];//边i的起点在edges中的编号
    
        void init(int n) {
            for (int i = 0; i < n; i ++) 
                G[i].clear();
            edges.clear();
        }
    
        void addEdges(int from, int to, int cap) {
            edges.push_back(Edge(from, to, cap, 0));
            edges.push_back(Edge(to, from, 0, 0));//反向弧
            m = edges.size();
            G[from].push_back(m-2);//新加入的边(from-to)是节点from的第G[from].size()条边,在edges中是第m-1条
            G[to].push_back(m-1);//新加入的边(to-from)是节点to的第G[to].size()条边,在edges中是第m条
        }
    
        int MaxFlow(int s, int t) {
            int flow = 0;
            for(;;) {
                memset(a, 0, sizeof(a));
                queue<int> Q;
                Q.push(s);
                a[s] = INF;
                while (!Q.empty()) {
                    int x = Q.front();//当前处理节点
                    Q.pop();
                    for(int i = 0; i < G[x].size(); i ++) {
                        Edge &e = edges[G[x][i]];//当前节点的第i条边
                        if(!a[e.to] && e.cap > e.flow) {//如果起点到此边终点可改进,并且边的容量大于流量
                            p[e.to] = G[x][i];//此边的起点是edges的第几条边,方便最后从终点到起点检索
                            a[e.to] = min(a[x], e.cap-e.flow);//取之前的可改进量和当前边的可改进量最小值,为从起点到此边终点的最大可改进量
                            Q.push(e.to);
                        }
                    }
                    if(a[t]) break;//遍历到终点
                }
                if(!a[t]) break;//无可改进量,返回结果
                for (int u = t; u !=s; u = edges[p[u]].from ) {
                    edges[p[u]].flow += a[t];//
                    edges[p[u]^1].flow -= a[t];
                }//通过更新flow建立新的残量网络
                flow += a[t];//累加本次循环的可改进量
            }
            return flow;
        }
    
    }

     主要思路是通过BFS遍历网络,将每次的可改进量从最优路径中删除,直到无可改进量为止。每次的可改进量累加,就是最终网络最大流

    下面是Dinic算法

    struct Dinic {
        int n, m, s, t;//节点数,边数(包括反向弧),源点编号和终点编号
        vector<Edge> edges;//边表, edges[e]h和edges[e^1] 互为反向弧
        vector<int> G[maxn];
        bool vis[maxn];
        int d[maxn];//起点到i的距离
        int cur[maxn];//当前弧下标
    
        bool BFS() {
            memset(vis, 0, sizeof(vis));
            queue<int> Q;
            Q.push(s);
            d[s] = 0;
            vis[s] = 1;
            while(!Q.empty()) {
                int x = Q.front(); Q.pop();
                for (int i = 0; i < G[x].size(); i ++) {
                    Edge &e = edges[G[x][i]];
                    if(!vis[e.to] && e.cap >e.flow) {
                        vis[e.to] = 1;
                        d[e.to] = d[x] + 1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
    
        int DFS(int x, int a) {
            if (x == t || a == 0) return a;
            int flow = 0, f;
            for (int &i = cur[x]; i < G[x]; i ++) {
                Edge &e = edges[G[x][i]];
                if (d[x] + 1 == d[e.to] && (f == DFS(e.to, min(a, e.cap - e.flow))) > 0) {
                    e.flow += f;
                    edges[G[x][i]^1].flow -= f;
                    flow += f;
                    a -= f;
                    if(a == 0) break;
    
                }
            }
            return flow;
        }
    
        int MaxFlow(int s, int t) {
            this->s = s; this    ->t = t;
            int flow = 0;
            while(BFS()) {
                memset(cur, 0, sizeof(cur));
                flow += DFS(S, INF);
    
            }
            return flow;
        }
    }

    2 Bellman-Ford算法解决最小费用最大流问题

    struct Edge {
        int from;//起点 
        int to;//终点
        int cap;//容量 
        int flow;//流量
        int cost;//费用
        Edge(int u, int v, int c, int f, int s):form(u), to(v), cap(c), flow(f), cost(s){}
    };
    
    struct MCMF {
        int n, m;
        vector<Edge> edges;//边数的两倍,正向+反向
        vector<int> G[maxn];//邻接表,G[i][j]表示节点i的第j条边在e数组中的序号
        int a[maxn];//起点到i的可改进量(残量)
        int p[maxn];//边i的起点在edges中的编号
        int d[maxn];//Bellman-Ford
    
    
        void init(int n) {
            this->n = n
            for (int i = 0; i < n; i ++) 
                G[i].clear();
            edges.clear();
        }
    
        void addEdges(int from, int to, int cap, int cost) {
            edges.push_back(Edge(from, to, cap, 0, cost));
            edges.push_back(Edge(to, from, 0, 0, -cost));//反向弧
            m = edges.size();
            G[from].push_back(m-2);//新加入的边(from-to)是节点from的第G[from].size()条边,在edges中是第m-1条
            G[to].push_back(m-1);//新加入的边(to-from)是节点to的第G[to].size()条边,在edges中是第m条
        }
    
        int BellmanFord(int s, int t, int &flow, long cost) {
            for (int i = 0; i < n; i++) d[i] = INF;
            memset(inq, 0, sizeof(inq));
            d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
            int flow = 0;
            queue<int> Q;
            Q.push(s);
            while (!Q.empty()) {
                int u = Q.front();//当前处理节点
                Q.pop();
                inq[u] = 0;
                for(int i = 0; i < G[u].size(); i ++) {
                    Edge &e = edges[G[u][i]];//当前节点的第i条边
                    if(d[e.to] > d[u] + e.cost && e.cap > e.flow) {//如果起点到此边终点可改进,并且边的容量大于流量
                        d[e.to] = d[u] + e.cost;//增加cost
                        p[e.to] = G[x][i];//此边的起点是edges的第几条边,方便最后从终点到起点检索
                        a[e.to] = min(a[x], e.cap-e.flow);//取之前的可改进量和当前边的可改进量最小值,为从起点到此边终点的最大可改进量
                        if(!inq[e.to]) {
                            Q.push(e.to);
                            inq[e.to] = 1;
                        }    
                    }
                }
            }
            if(d[t] == INF) return false;//无可改进量,返回结果
            flow += a[t];
            cost += (long)d[t] * (long)a[t];
            for (int u = t; u !=s; u = edges[p[u]].from ) {
                edges[p[u]].flow += a[t];//
                edges[p[u]^1].flow -= a[t];
            }//通过更新flow建立新的残量网络
                
            return true;
        }
    
        int MincostMaxFlow(int s, int t, long &cost) {
            int flow = 0;
            int cost = 0;
            while(BellmanFord(s, t, flow, cost));
            return flow;
        }
    
    }

    和增广路算法不同的是需要统计每次增广算法增加的费用,保证在最大流前提下,费用最小。

  • 相关阅读:
    替换html里面的 及解决记事本中的每个段落只有一行的情形
    关于 'list' object has no attribute 'select'
    python写爬虫的弯路
    将博客搬至CSDN
    转载:如何让spring mvc web应用启动时就执行
    java开发人员,最应该学习和熟练使用的工具类。google guava.(谷歌 瓜娃)
    解决svn问题:Wrong committed revision number: -1
    生产环境中,数据库升级维护的最佳解决方案flyway
    在JaveWeb项目中配置Spring 匿名访问时,匹配规则的变相实现/*
    nexus的使用
  • 原文地址:https://www.cnblogs.com/lichongjie/p/6861087.html
Copyright © 2020-2023  润新知