網路流24題(十七)
阿新 • • 發佈:2021-10-26
網路流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。
- 從S向每個\(X_i\)
- 從每個\(Y_i\)向T連一條容量為商店所需貨物數量\(b_i\),費用為0的有向邊。
- 從每個\(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; }