[模板]最小费用最大流

最小费用最大流

(以下来自百度百科)
最小费用最大流问题是经济学和管理学中的一类典型问题。在一个网络中每段路径都有“容量”和“费用”两个限制的条件下,此类问题的研究试图寻找出:流量从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; }

 

posted @ 2018-01-06 09:37  xayata  阅读(161)  评论(0编辑  收藏  举报