E - Minimum Cost(最小费用最大流)

Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (marked from 1 to M), each provides K different kinds of goods (marked from 1 to K). Once shopkeepers order goods, Dearboy should arrange which supply place provide how much amount of goods to shopkeepers to cut down the total cost of transport.

It’s known that the cost to transport one unit goods for different kinds from different supply places to different shopkeepers may be different. Given each supply places’ storage of K kinds of goods, N shopkeepers’ order of K kinds of goods and the cost to transport goods for different kinds from different supply places to different shopkeepers, you should tell how to arrange the goods supply to minimize the total cost of transport.
Input
The input consists of multiple test cases. The first line of each test case contains three integers N, M, K (0 < N, M, K < 50), which are described above. The next N lines give the shopkeepers’ orders, with each line containing K integers (there integers are belong to [0, 3]), which represents the amount of goods each shopkeeper needs. The next M lines give the supply places’ storage, with each line containing K integers (there integers are also belong to [0, 3]), which represents the amount of goods stored in that supply place.

Then come K integer matrices (each with the size N * M), the integer (this integer is belong to (0, 100)) at the i-th row, j-th column in the k-th matrix represents the cost to transport one unit of k-th goods from the j-th supply place to the i-th shopkeeper.

The input is terminated with three "0"s. This test case should not be processed.
Output
For each test case, if Dearboy can satisfy all the needs of all the shopkeepers, print in one line an integer, which is the minimum cost; otherwise just output “-1”.
先给出N个商店,M个供应商,每个商店要从供应商那进K种货物,而且进货需求不同,而每个供应商的每种货物到不同商店有不同的价格,每个供应商货物库存有限,问在满足每个商店需求的情况下的最小费用,若不满足输出-1。
输入第一行为N,M,K。
接下来N行每行K个数,第i行第j个数代表商店i需要货物j的数量(在0到3之间)。
接下来M行每行K个数,第i行第j个数代表供货商i的货物j的库存数量(在0到3之间)。
接下来给出k个n*m的矩阵,第i个矩阵的第j行第l个数代表货物i从供货商l到商店j的价格(在1到100之间)。

解答:
由于是按物品给出k个矩阵,可以分开按每个物品来求最小费用最大流,设置源点为0,汇点为n+m+1。
从源点到每个商店建边,容量为需求量,费用为0.
每个商店到供货商建边,容量为无限,费用为进货价格。
每个供货商到汇点建边,容量为库存,费用为0.
跑最小费用最大流,最后将总费用加起来。

#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=10000+5;
const int maxm=100000+5;
int head[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn],vis[maxn],ne,n,m,k,S,T,ans,maxflow,mincost;

void init()
{
	ans=0;
	ne=0;
	memset(head,-1,sizeof(head));
}
struct edge{int v,w,nxt,cost;}G[maxm<<1];
void add(int u,int v,int w,int cost)
{
	G[ne]=(edge){v,w,head[u],cost};
	head[u]=ne++;
	G[ne]=(edge){u,0,head[v],-cost};
	head[v]=ne++;
}
int spfa()
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(flow,0x3f,sizeof(flow));
	queue<int> q;
	q.push(S);
	dis[S]=0;
	pre[T]=-1;
	vis[S]=1;
	while(!q.empty())
	{
		int u=q.front();
		vis[u]=0;
		q.pop();
		for(int i=head[u];i!=-1;i=G[i].nxt)
		{
			int v=G[i].v;
			if(dis[v]>dis[u]+G[i].cost&&G[i].w>0)
			{
				dis[v]=dis[u]+G[i].cost;
				pre[v]=u;
				last[v]=i;
				flow[v]=min(flow[u],G[i].w);
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	//return dis[T]<=0; 最小费用可行流 
	return pre[T]!=-1;
}

int MCMF()
{
	
	while(spfa())
	{
		int u=T;
		maxflow+=flow[T];
		mincost+=flow[T]*dis[T];
		while(u!=S)
		{
			G[last[u]].w-=flow[T];
			G[last[u]^1].w+=flow[T];
			u=pre[u];
		}
	}
}
struct needd
{
	int a[100];
}need[100];
struct supply
{
	int b[100];
}sup[100];
int sc[80][80][80];
int main()
{
	
	while(~scanf("%d%d%d",&n,&m,&k)&&(n+m+k))
	{	
		maxflow=0,mincost=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=k;j++)
			{
				scanf("%d",&need[i].a[j]);
				
			}
		}
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=k;j++)
			{
				scanf("%d",&sup[i].b[j]);
			}
		}
		for(int i=1;i<=k;i++)
		{
			for(int j=1;j<=n;j++)
			{
				for(int l=1;l<=m;l++)
				{
					scanf("%d",&sc[i][j][l]);
				}
			}
		}
		S=0;
		T=n+m+1;
		int flag=1;
		for(int i=1;i<=k;i++)
		{
			int xx=0,yy=0;
			init();
			for(int j=1;j<=n;j++)
			{
				add(S,j,need[j].a[i],0);
				xx+=need[j].a[i];
			}
			for(int j=1;j<=m;j++)
			{
				add(n+j,T,sup[j].b[i],0);
				yy+=sup[j].b[i];
			}
			for(int j=1;j<=n;j++)
			{
				for(int l=1;l<=m;l++)
				{
					add(j,l+n,inf,sc[i][j][l]);
				}
			}
			if(xx>yy)
			{
				flag=0;
				break;
			}
			MCMF();
		}
		if(flag) printf("%d\n",mincost);
		else printf("-1\n");
	}
}

猜你喜欢

转载自blog.csdn.net/zufe_cst/article/details/86494611