6011. 「网络流 24 题」运输问题
这道题巨水无比啊.
人类未来的饮用水就靠这道题供给了.
先来理解下题意.
有\(m\)个仓库,第\(i\)个仓库有\(a_i\)个货物.有\(n\)个商店,第\(i\)个商店需要\(b_i\)个货物.从第\(i\)个仓库运到第\(j\)个商店的费用是\(c_{ij}\).
于是网络流的建模就出来了,源点连向仓库,流量为\(a_i\),费用为\(0\).仓库与商店之间相连,流量为\(INF\),费用为\(c_{ij}\),商店与汇点相连,流量为\(b_i\),费用为\(0\).
跑一遍\(MCMF\)求出最小费用.
然后再给费用取反,再跑一遍\(MCMF\)求出最大费用.
代码:
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "iostream"
#include "cmath"
#include "queue"
#define debug(x) printf("debug:%lld\n",x)
#define ll long long
#define INF 2147483647
using namespace std;
struct edge
{
ll to,next,flow,cost;
}e1[500010],e2[500010];
queue<ll>q1,q2;
ll m,n,start,end,size1,size2,mincost,maxcost;//m个仓库,n个商店.
ll head1[10010],dis1[10010],flow1[10010],last1[10010],pre1[10010];
ll head2[10010],dis2[10010],flow2[10010],last2[10010],pre2[10010];
bool flag1[10010];
bool flag2[10010];
inline void EdgeAdd1(ll,ll,ll,ll);
inline void EdgeAdd2(ll,ll,ll,ll);
inline void MCMF1();
inline void MCMF2();
inline bool SPFA1();
inline bool SPFA2();
signed main(void)
{
memset(head1,-1,sizeof(head1));
memset(head2,-1,sizeof(head2));
scanf("%lld%lld",&m,&n);
start=0;
end=m+n+1;
for(ll _=1;_<=m;_++)
{
ll val;
scanf("%lld",&val);
EdgeAdd1(start,_,val,0);
EdgeAdd1(_,start,0,0);
EdgeAdd2(start,_,val,0);
EdgeAdd2(_,start,0,0);
}
for(ll _=1;_<=n;_++)
{
ll val;
scanf("%lld",&val);
EdgeAdd1(_+m,end,val,0);
EdgeAdd1(end,_+m,0,0);
EdgeAdd2(_+m,end,val,0);
EdgeAdd2(end,_+m,0,0);
}
for(ll _=1;_<=m;_++)
{
for(ll __=1;__<=n;__++)
{
ll cost;
scanf("%lld",&cost);
EdgeAdd1(_,__+m,INF,cost);
EdgeAdd1(__+m,_,0,-cost);
EdgeAdd2(_,__+m,INF,-cost);
EdgeAdd2(__+m,_,0,cost);
}
}
MCMF1();
MCMF2();
printf("%lld\n%lld\n",mincost,-maxcost);
return 0;
}
inline void EdgeAdd1(ll from,ll to,ll flow,ll cost)
{
e1[size1].to=to;
e1[size1].flow=flow;
e1[size1].cost=cost;
e1[size1].next=head1[from];
head1[from]=size1++;
}
inline void EdgeAdd2(ll from,ll to,ll flow,ll cost)
{
e2[size2].to=to;
e2[size2].flow=flow;
e2[size2].cost=cost;
e2[size2].next=head2[from];
head2[from]=size2++;
}
inline void MCMF1()
{
while(SPFA1())
{
ll now=end;
mincost+=flow1[end]*dis1[end];
while(now!=start)
{
e1[last1[now]].flow-=flow1[end];
e1[last1[now]^1].flow+=flow1[end];
now=pre1[now];
}
}
}
inline void MCMF2()
{
while(SPFA2())
{
ll now=end;
maxcost+=flow2[end]*dis2[end];
while(now!=start)
{
e2[last2[now]].flow-=flow2[end];
e2[last2[now]^1].flow+=flow2[end];
now=pre2[now];
}
}
}
inline bool SPFA1()
{
memset(dis1,0x3f,sizeof(dis1));
memset(flag1,false,sizeof(flag1));
memset(flow1,0x3f,sizeof(flow1));
q1.push(start);
pre1[end]=-1;
dis1[start]=0;
flag1[start]=true;
while(q1.empty()==false)
{
ll from=q1.front();
q1.pop();
flag1[from]=false;
for(ll _=head1[from];_!=-1;_=e1[_].next)
{
ll to=e1[_].to;
ll cost=e1[_].cost;
ll flow_=e1[_].flow;
if(flow_>0&&dis1[to]>dis1[from]+cost)
{
dis1[to]=dis1[from]+cost;
pre1[to]=from;
last1[to]=_;
flow1[to]=min(flow1[from],flow_);
if(flag1[to]==false)
{
q1.push(to);
flag1[to]=true;
}
}
}
}
return pre1[end]==-1?false:true;
}
inline bool SPFA2()
{
memset(flag2,false,sizeof(flag2));
memset(dis2,0x3f,sizeof(dis2));
memset(flow2,0x3f,sizeof(flow2));
q2.push(start);
flag2[start]=true;
dis2[start]=0;
pre2[end]=-1;
while(!q2.empty())
{
ll from=q2.front();
q2.pop();
flag2[from]=false;
for(ll _=head2[from];_!=-1;_=e2[_].next)
{
ll to=e2[_].to;
ll cost=e2[_].cost;
ll flow_=e2[_].flow;
if(flow_>0&&dis2[to]>dis2[from]+cost)
{
dis2[to]=dis2[from]+cost;
pre2[to]=from;
last2[to]=_;
flow2[to]=min(flow2[from],flow_);
if(flag2[to]==false)
{
q2.push(to);
flag2[to]=true;
}
}
}
}
return pre2[end]==-1?false:true;
}