[网络流24题]运输问题

题目:洛谷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
",mincost(0,n+m+1));
	memcpy(e,ee,sizeof e);
	printf("%d
",-mincost(0,n+m+1));
	return 0;
} 
原文地址:https://www.cnblogs.com/Mrsrz/p/8330990.html