网络流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\)连一条容量为仓库中货物数量\(a_i\),费用为0的有向边。
- 从每个\(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;
}