题目:洛谷P4015、codevs1914。
题目大意:有n个仓库和m个商店,每个仓库存有不同的货物,每个商店需要不同的货物。
现在商店与仓库之间都有通道,可以供应的货物数量不限。
但每个仓库运往每个商店1个货物的费用不同。
现在问你最小的费用使得每个商店都能满足需求。
供货量等于收货量,且数据保证正确。
解题思路:最小费用最大流。
首先建出二分图,然后建立超源和超汇,则此题就变为最小费用最大流的裸题了。
第一问,求费用即可。
第二问,把边的费用取相反数,然后费用流过程一个字节不用改,再跑一边,最后费用取相反数即可。
C++ Code:
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
std::queue<int>q;
int n,m,cnt=-1,pre_e[255],head[255],d[255],a[255];
bool vis[255];
struct edge{
int from,to,cap,dis,nxt;
}e[300005],ee[300005];
inline int addedge(int u,int v,int cap,int dis){
e[++cnt]=(edge){u,v,cap,dis,head[u]};
ee[cnt]=(edge){u,v,cap,-dis,head[u]};
head[u]=cnt;
e[++cnt]=(edge){v,u,0,-dis,head[v]};
ee[cnt]=(edge){v,u,0,dis,head[v]};
head[v]=cnt;
}
bool maxflow(int s,int t,int& flow,int& cost){
memset(d,0x3f,sizeof d);
memset(a,0x3f,sizeof a);
memset(vis,0,sizeof vis);
memset(pre_e,0,sizeof pre_e);
d[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=e[i].nxt)
if(e[i].cap&&d[e[i].to]>d[u]+e[i].dis){
d[e[i].to]=d[u]+e[i].dis;
a[e[i].to]=(a[u]>e[i].cap)?e[i].cap:a[u];
pre_e[e[i].to]=i;
if(!vis[e[i].to]){
vis[e[i].to]=true;
q.push(e[i].to);
}
}
}
if(d[t]==inf)return 0;
flow+=a[t];
cost+=a[t]*d[t];
for(int i=t;i!=s;i=e[pre_e[i]].from){
e[pre_e[i]].cap-=a[t];
e[pre_e[i]^1].cap+=a[t];
}
return 1;
}
int mincost(int s,int t){
int flow=0,cost=0;
while(maxflow(s,t,flow,cost));
return cost;
}
int main(){
memset(head,-1,sizeof head);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
int x;
scanf("%d",&x);
addedge(0,i,x,0);
}
for(int i=1;i<=m;++i){
int x;
scanf("%d",&x);
addedge(i+n,n+m+1,x,0);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
int x;
scanf("%d",&x);
addedge(i,j+n,inf,x);
}
printf("%d\n",mincost(0,n+m+1));
memcpy(e,ee,sizeof e);
printf("%d\n",-mincost(0,n+m+1));
return 0;
}