1. 程式人生 > 其它 >網路流24題(十七)

網路流24題(十七)

網路流24題(十七)

十七、運輸問題

題目描述

W 公司有 m 個倉庫和 n 個零售商店。第 i 個倉庫有 \(a_i\)​ 個單位的貨物;第 j 個零售商店需要 \(b_j\) 個單位的貨物。

貨物供需平衡,即\(\sum\limits_{i=1}^{m}a_i=\sum\limits_{j=1}^{n}b_j\)​。

從第 i 個倉庫運送每單位貨物到第 j 個零售商店的費用為 \(c_{ij}\)​​​ 。

試設計一個將倉庫中所有貨物運送到零售商店的運輸方案,使總運輸費用最少。

輸入格式

第 1 行有 2 個正整數 m 和 n,分別表示倉庫數和零售商店數。

接下來的一行中有 m 個正整數 \(a_i\)​,表示第 i 個倉庫有 \(a_i\)​個單位的貨物。

再接下來的一行中有 n 個正整數 \(b_j\)​,表示第 j 個零售商店需要 \(b_j\) 個單位的貨物。

接下來的 m 行,每行有 n 個整數,表示從第 i 個倉庫運送每單位貨物到第 j 個零售商店的費用 \(c_{ij}\)

輸出格式

兩行分別輸出最小運輸費用和最大運輸費用。

題解

模型

裸的二分圖費用流,極其簡單

建圖

把所有倉庫看做二分圖中頂點\(X_i\),所有零售商店看做二分圖中頂點\(Y_i\),建立附加源S匯T。

  1. 從S向每個\(X_i\)
    連一條容量為倉庫中貨物數量\(a_i\),費用為0的有向邊。
  2. 從每個\(Y_i\)向T連一條容量為商店所需貨物數量\(b_i\),費用為0的有向邊。
  3. 從每個\(X_i\)向每個\(Y_j\)連線一條容量為無窮大,費用為\(c_{ij}\)的有向邊。

求最小費用最大流,最小費用流值就是最少運費,求最大費用最大流,最大費用流值就是最多運費。

程式碼

#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
using namespace std;
#define ll long long
const ll inf = 0x3f3f3f3f;
const int N = 5000,M = 5e4+50;
ll head[N],cnt = 1;
struct Edge{
    ll to,w,cost,nxt;
}edge[M*2];
void add(ll u,ll v,ll w,ll c){
    edge[++cnt] = {v,w,c,head[u]};
    head[u] = cnt;
}
void add2(ll u,ll v,ll w,ll cost){
    add(u,v,w,cost);
    add(v,u,0,-cost);
}
ll s,t,dis[N],cur[N];
bool inq[N],vis[N];
queue<ll>Q;
bool spfa(){
    while(!Q.empty()) Q.pop();
    copy(head,head+N,cur);
    fill(dis,dis+N,inf);
    dis[s] = 0;
    Q.push(s);
    while(!Q.empty()){
        ll p = Q.front();
        Q.pop();
        inq[p] = false;
        for(ll e = head[p];e;e = edge[e].nxt){
            ll to = edge[e].to,vol = edge[e].w;
            if(vol > 0 && dis[to]>dis[p]+edge[e].cost){
                dis[to] = dis[p] + edge[e].cost;
                if(!inq[to]){
                    Q.push(to);
                    inq[to] = true;
                }
            }
        }
    }
    return dis[t] != inf;
}
ll dfs(ll p = s,ll flow = inf){
    if(p == t) return flow;
    vis[p] = true;
    ll rmn = flow;
    for(ll eg = cur[p];eg && rmn;eg = edge[eg].nxt){
        cur[p] = eg;
        ll to = edge[eg].to,vol = edge[eg].w;
        if(vol > 0 && !vis[to]&&dis[to] == dis[p]+edge[eg].cost){
            ll c = dfs(to,min(vol,rmn));
            rmn -= c;
            edge[eg].w -= c;
            edge[eg^1].w += c;
        }
    }
    vis[p] = false;
    return flow-rmn;
}
ll maxflow,mincost;
void dinic(){
    maxflow = 0,mincost = 0;
    while(spfa()){
        ll flow = dfs();
        maxflow += flow;
        mincost += dis[t]*flow;
    }
}
ll n,m;
ll a[N],b[N],c[N][N];
void init1(){
    for(ll i = 1;i <= m;i++)add2(s,i,a[i],0);
    for(ll i = 1;i <= n;i++)add2(i+m,t,b[i],0);
    for(ll i = 1;i <= m;i++){
        for(ll j = 1;j <= n;j++){
            add2(i,j+m,inf,c[i][j]);
        }
    }
    dinic();
    cout<<mincost<<endl;
}
void init2(){
    memset(head,0, sizeof head);
    cnt = 1;
    for(ll i = 1;i <= m;i++)add2(s,i,a[i],0);
    for(ll i = 1;i <= n;i++)add2(i+m,t,b[i],0);
    for(ll i = 1;i <= m;i++){
        for(ll j = 1;j <= n;j++){
            add2(i,j+m,inf,-c[i][j]);
        }
    }
    dinic();
    cout<<-mincost<<endl;
}
int main(){
    //ios::sync_with_stdio(false);
    cin>>m>>n;
    s = 0,t = n+m+1;
    for(ll i = 1;i <= m;i++)cin>>a[i];
    for(ll j = 1;j <= n;j++)cin>>b[j];
    for(ll i = 1;i <= m;i++){
        for(ll j = 1;j <= n;j++){
            cin>>c[i][j];
        }
    }
    init1();
    init2();
    return 0;
}