【网络流24题】运输问题(最小费用最大流)

题意

W 公司有 m m m 个仓库和 n n n 个零售商店。第 i i i 个仓库有 a i a_i ai​​ 个单位的货物;第 j j j 个零售商店需要 b j b_j bj​​ 个单位的货物。货物供需平衡,即 ∑ i = 1 m a i = ∑ j = 1 n b j ​ ​ \sum\limits_{i = 1} ^ m a_i = \sum\limits_{j = 1} ^ n b_j ​​ i=1mai=j=1nbj​​。从第 i i i 个仓库运送每单位货物到第 j j j 个零售商店的费用为 c i j c_{ij} cij​​。试设计一个将仓库中所有货物运送到零售商店的运输方案,使总运输费用最少。

题解

最小费用最大流

代码

普通的最小费用最大流

#include 
using namespace std;
const int nmax = 10000;
const int INF = 0x3f3f3f3f;
typedef int valtype;
struct MCMF{
    valtype final_flow,final_cost;
    int tot,S,T;
    bool inque[nmax];
    int head[nmax], pre_edge[nmax],pre_index[nmax];
    valtype add_flow[nmax], dis[nmax];
    struct edge{int to,nxt;valtype cap,flow,cost;}e[nmax<<1];
    void init(int S, int T){
        memset(head,-1,sizeof head);
        tot = 0;
        this->S = S, this->T = T;
    }
    void add_edge(int u, int v, valtype cap, valtype cost){
        e[tot].to = v, e[tot].nxt = head[u], e[tot].flow = 0, e[tot].cap = cap, e[tot].cost = cost, head[u] = tot++;
        e[tot].to = u, e[tot].nxt = head[v], e[tot].flow = 0, e[tot].cap = 0, e[tot].cost = -cost, head[v] = tot++;
    }
    bool spfa(){
        for(int i = S;i<=T;++i) inque[i] = false, dis[i] = i == S?0:INF;
        queue<int> q; q.push(S), inque[S] = true, add_flow[S] = INF;
        while(!q.empty()){
            int u = q.front(); q.pop(); inque[u] = false;
            for(int i = head[u];i!=-1;i=e[i].nxt){
                int v = e[i].to;
                if(e[i].cap > e[i].flow && dis[u] + e[i].cost < dis[v]){
                    dis[v] = dis[u] + e[i].cost, pre_edge[v] = i, pre_index[v] = u;
                    add_flow[v] = min(add_flow[u],e[i].cap - e[i].flow);
                    if(!inque[v]) q.push(v),inque[v] = true;
                }
            }
        }
        return dis[T] != INF;
    }
    void mincost_mxflow() {
        final_cost = final_flow = 0;
        while(spfa()){
            final_flow += add_flow[T];
            final_cost += add_flow[T] * dis[T];
            int now = T;
            while(now != S){
                e[pre_edge[now]].flow += add_flow[T];
                e[pre_edge[now]^1].flow -= add_flow[T];
                now = pre_index[now];
            }
        }
    }
}mcmf;
int n, m;
int a[105], b[105];
int cost[105][105];
int main() {
    scanf("%d %d", &n, &m);
    int s = 0, t = n + m + 1, tmp;
    mcmf.init(s, t);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        mcmf.add_edge(s, i, a[i], 0);
    }
    for(int i = 1; i <= m; ++i) {
        scanf("%d", &b[i]);
        mcmf.add_edge(n + i, t, b[i],  0);
    }
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            scanf("%d", &cost[i][j]);
            mcmf.add_edge(i, j + n, a[i], cost[i][j]);
        }
    }
    mcmf.mincost_mxflow();
    printf("%d\n", mcmf.final_cost);
    mcmf.init(s, t);
    for(int i = 1; i <= n; ++i)
        mcmf.add_edge(s, i, a[i], 0);
    for(int i = 1; i <= m; ++i)
        mcmf.add_edge(n + i, t, b[i], 0);
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            mcmf.add_edge(i, j + n, a[i], -cost[i][j]);
        }
    }
    mcmf.mincost_mxflow();
    printf("%d\n", -mcmf.final_cost);
}

zkw最小费用最大流

#include 
using namespace std;
const int nmax = 10000;
const int INF = 0x3f3f3f3f;
typedef int valtype;
struct zkwflow {
    struct edge {
        valtype cost, cap;
        int nxt, re, to;
    }e[nmax];
    int head[nmax], tot, vis[nmax], s, t;
    valtype ans, cost, maxflow;
    void init(int s, int t) {
        memset(head, -1, sizeof(head));
        tot = 0;
        ans = cost = maxflow = 0;
        this->s = s, this->t = t;
    }
    void add_edge(int u, int v, valtype cap, valtype cost) {
        e[tot].to = v;
        e[tot].cap = cap;
        e[tot].cost = cost;
        e[tot].re = tot + 1;
        e[tot].nxt = head[u];
        head[u] = tot++;
        e[tot].to = u;
        e[tot].cap = 0;
        e[tot].cost = -cost;
        e[tot].re = tot - 1;
        e[tot].nxt = head[v];
        head[v] = tot++;
    }
    valtype aug(int u, valtype f) {
        if(u == t) {
            ans += cost * f;
            maxflow += f;
            return f;
        }
//        printf("debug %d %d\n", u, f);
        vis[u] = 1;
        valtype tmp = f;
        for(int i = head[u]; i != -1; i = e[i].nxt)
            if(e[i].cap && !e[i].cost && !vis[e[i].to]) {
                valtype delta = aug(e[i].to, tmp < e[i].cap ? tmp : e[i].cap);
                e[i].cap -= delta;
                e[e[i].re].cap += delta;
                tmp -= delta;
                if(!tmp) return f;
            }
        return f - tmp;
    }
    bool modlabel(int n) {
        valtype delta = INF;
        for(int u = 1; u <= n; u++)
            if(vis[u])
                for(int i = head[u]; i != -1; i = e[i].nxt)
                    if(e[i].cap && !vis[e[i].to] && e[i].cost < delta) delta = e[i].cost;
        if(delta == INF) return false;
        for(int u = 1; u <= n; u++)
            if(vis[u])
                for(int i = head[u]; i != -1; i = e[i].nxt)
                    e[i].cost -= delta, e[e[i].re].cost += delta;
        cost += delta;
        return true;
    }
    valtype costflow() {
        do {
            do {
                memset(vis, 0, sizeof(vis));
            }while(aug(s, INF));
        }while(modlabel(t));
        return ans;
    }
}zkw;
int n, m;
int a[105], b[105];
int cost[105][105];
int main() {
    scanf("%d %d", &n, &m);
    int s = n + m + 1, t = n + m + 2;
    zkw.init(s, t);
    for(int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        zkw.add_edge(s, i, a[i], 0);
    }
    for(int i = 1; i <= m; ++i) {
        scanf("%d", &b[i]);
        zkw.add_edge(n + i, t, b[i],  0);
    }
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            scanf("%d", &cost[i][j]);
            zkw.add_edge(i, j + n, a[i], cost[i][j]);
        }
    }
    zkw.costflow();
    printf("%d\n", zkw.ans);
    zkw.init(s, t);
    for(int i = 1; i <= n; ++i)
        zkw.add_edge(s, i, a[i], 0);
    for(int i = 1; i <= m; ++i)
        zkw.add_edge(n + i, t, b[i], 0);
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= m; ++j) {
            zkw.add_edge(i, j + n, a[i], -cost[i][j]);
        }
    }
    zkw.costflow();
    printf("%d\n", -zkw.ans);
}

你可能感兴趣的:(图论---网络流)