zoukankan      html  css  js  c++  java
  • [模板]最小费用最大流

    最小费用最大流

    (以下来自百度百科)
    最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有“容量”和“费用”两个限制的条件下,此类问题的研究试图寻找出:流量从A到B,如何选择路径、分配经过路径的流量,可以在流量最大的前提下,达到所用的费用最小的要求。如n辆卡车要运送物品,从A地到B地。由于每条路段都有不同的路费要缴纳,每条路能容纳的车的数量有限制,最小费用最大流问题指如何分配卡车的出发路径可以达到费用最低,物品又能全部送到。

    一个网络流图中最大流的流量max_flow是唯一的,但是当每一条都有一个费用时,达到max_flow的费用不一定是唯一的,最小费用最大流就是当流量最大时,费用最小为多少。

    即每条边都设置一个费用cost,表示单位流量流经该边时会导致花费cost。

    算法实现思路:
    采用贪心的思想,每次找到一条从源点到达汇点的路径,增加流量,且该条路径满足使得增加的流量的花费最小,直到无法找到一条从源点到达汇点的路径,算法结束。
    由于最大流量有限,每执行一次循环流量都会增加,因此该算法肯定会结束,且同时流量也必定会达到网络的最大流量;同时由于每次都是增加的最小的花费,即当前的最小花费是所有到达当前流量flow时的花费最小值,因此最后的总花费最小。
    //形象感知

    求解步骤
    (1)找到一条从源点到达汇点的“距离最短”的路径,“距离”使用该路径上的边的单位费用之和来衡量。
    (2)然后找出这条路径上的边的容量的最小值f,则当前最大流max_flow扩充f,同时当前最小费用min_cost扩充f*min_dist(s,t)
    (3)将这条路径上的每条正向边的容量都减少f,每条反向边的容量都增加f。
    (4)重复(1)--(3)直到无法找到从源点到达汇点的路径。

    我们每次要更新的时候就可以在费用网络上跑最短路。因为有负权的问题,我们可以用spfa跑。

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    
    #define gc getchar()
    #define oo 99999999;
    
    using namespace std;
    const int N = 5010;
    
    int n, m, S, T, now;
    int head[N], dis[N], pre[N];
    bool vis[N];
    struct Node{int u, v, cost, flow, nxt;} G[(N * 10) << 1];
    
    queue <int> Q;
    
    inline int read(){
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline void add(int u, int v, int cost, int flow){
        G[now].u = u; G[now].v = v; G[now].cost = cost; G[now].flow = flow;
           G[now].nxt = head[u]; head[u] = now ++;
    }
    
    inline bool spfa(int start, int endd){
        for(int i = 1; i <= n; i ++) vis[i] = 0, dis[i] = oo;
        dis[start] = 0;
        Q.push(start);
        while(!Q.empty()){
            int topp = Q.front();
            Q.pop(); vis[topp] = 0;
            for(int i = head[topp]; ~ i; i = G[i].nxt){
                int v = G[i].v;
                if(dis[v] > dis[topp] + G[i].cost && G[i].flow > 0){
                    dis[v] = dis[topp] + G[i].cost; 
                    pre[v] = i;
                    if(!vis[v]) vis[v] = 1, Q.push(v);
                }
            }
        }
        return dis[endd] != oo;
    }
    
    inline void Mfmc(int & F, int & C){
        while(spfa(S, T)){
            int endd = T, Now;
            int min_f = oo;
            while(1) {
                Now = pre[endd];
                min_f = min(min_f, G[Now].flow);
                if(G[Now].u == S) break;
                endd = G[Now].u;
            }
            F += min_f; C += dis[T] * min_f;
            endd = T;
            while(1){
                Now = pre[endd];
                G[Now].flow -= min_f;
                G[Now ^ 1].flow += min_f;
                if(G[Now].u == S) break;
                endd = G[Now].u;
            }
        }
    }
    
    int main()
    {
        n = read(); m = read(); S = read(); T = read();
        for(int i = 1; i <= n; i ++) head[i] = -1;
        for(int i = 1; i <= m; i ++) {
            int u = read(), v = read(), flow = read(), cost = read();
            add(u, v, cost, flow); add(v, u, - cost, 0);
        }
        int Max_flow(0), Min_cost(0);
        Mfmc(Max_flow, Min_cost);
        printf("%d %d", Max_flow, Min_cost);
        return 0;
    }
    /*
    4 5 4 3
    4 2 30 2
    4 3 20 3
    2 3 20 1
    2 1 30 9
    1 3 40 5
    */

    比较快,相对难写

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    const int N = 1e4 + 10;//dian
    const int NN = 1e5 + 10;//bian
    const int INF = 9999999;
    
    int head[N], dis[N], belong[N];
    bool vis[N];
    int n, m, S, T, ans_flow, ans_cost, now = 1;
    struct Node {
        int u, v, flow, cost, nxt;
    } E[NN];
    queue <int> Q;
    
    inline int read() {
        int x = 0, f = 1;
        char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-') f = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9') x = x * 10 + c -'0', c = getchar();
        return x * f;
    }
    
    inline void add(int u, int v, int flow, int cost) {
        E[now].u = u;
        E[now].v = v;
        E[now].flow = flow;
        E[now].cost = cost;
        E[now].nxt = head[u];
        head[u] = now ++;
    }
    
    int AP(int start, int minn) {
        if (start == S) return minn;
        int ret = AP(E[belong[start]].u, min(minn, E[belong[start]].flow));
        if (!E[belong[start] ^ 1].cost) {
            now = belong[start] ^ 1;
            add(start, E[belong[start]].u, 0, -E[belong[start]].cost);
        }
        E[belong[start]].flow -= ret;
        E[belong[start] ^ 1].flow += ret;
        return ret;
    }
    
    inline void MCMF() {
        while(1) {
            for (int i = 1; i <= n; i ++)
                dis[i] = INF, vis[i] = 0;
            dis[S] = 0;
            Q.push(S);
            while (!Q.empty()) {
                int topp = Q.front();
                Q.pop();
                vis[topp] = 0;
                for (int i = head[topp]; ~ i; i = E[i].nxt) {
                    if (dis[E[i].v] > dis[topp] + E[i].cost && E[i].flow) {
                        dis[E[i].v] = dis[topp] + E[i].cost;
                        belong[E[i].v] = i;
                        if (!vis[E[i].v]) {
                            vis[E[i].v] = 1;
                            Q.push(E[i].v);
                        }
                    }
                }
            }
            if (dis[T] == INF)
                break;
            int now_flow = AP(T, INF);
            ans_flow += now_flow;
            ans_cost += now_flow * dis[T];
        }
    }
    
    int main() 
    { n
    = read(); m = read(); S = read(); T = read(); for (int i = 1; i <= n; i ++) head[i] = -1; for (int i = 1; i <= m; i ++) { int au = read(); int av = read(); int aflow = read(); int acost = read(); ++ now; add(au, av, aflow, acost); } MCMF(); printf("%d %d", ans_flow, ans_cost); return 0; }
  • 相关阅读:
    Python基础篇 -- 列表
    Python基础篇 -- 字符串
    Python基础篇 -- if while 语句
    Python基础篇 -- 运算符和编码
    Python 入门基础
    Docker知识收藏
    秒表
    Emac
    Android开发
    shell 小工具
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8213376.html
Copyright © 2011-2022 走看看