POJ-2561-Minimum Cost(最小费用最大流,分治,MCMF,向前星建图)

题目链接:http://poj.org/problem?id=2516

Description

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".

Sample Input

1 3 3   
1 1 1
0 1 1
1 2 2
1 0 1
1 2 3
1 1 1
2 1 1

1 1 1
3
2
20

0 0 0

Sample Output

4
-1

题目大意:n个商店,m个仓库,k种物资;

多组输入,对于每组数据,输入n,m ,k;

然后是n行,商店的需要物资,

m行,仓库拥有的物资;

接下来,k个n*m的矩阵,表示第k个物资由 仓库m 运送到 商店n 的花费(单位花费)

解释样例:

一个商店,三个仓库,三种物资;

商店需要三种物资每样一个;

对于每个仓库,分别有对应物资的个数

仓库一:0 1 1 仓库二:1 2 2 仓库三:1 0 1,的物资

然后是三行,

1 2 3 第一种物资,分别由三个仓库运送到第一个商店的单价花费;

1 1 1第二种物资。。。

2 1 1第三种物资。。。

一开始我是想着直接建一个大图,如图:

大致就是这样,一个大图,直接一次跑完,会超时!!不用试了,好多人都试过了(包括我,吐血。。。)

题目中有一个隐含条件,就是每种物资是分开的,也就是说,一种物质的分配对其他物资是没有影响的,所以,我们将物资分开来求费用流,最后全部相加即可(建图建的我头疼啊!i,j,z傻傻分不清,样例一直不过。。。。)

物资分开建图:就相当于一个个小得 源-汇 (我圈起来了)组成的网络流。

ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<fstream>
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 998244353
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);
struct dots{
	int x,y;
}dots[110],dott[110];
struct node{
	int v,w,cost,nxt;
	node(int _v=0,int _w=0,int _cost=0,int _nxt=0):
    v(_v),w(_w),cost(_cost),nxt(_nxt){}
}edge[100010<<1];
int head[100010],ecnt;
int dis[100010],flow[100010],pre[100010],last[100010];
//	最小花费	流量			前驱		这条边 
int vis[100010];
int maxw,mincost;
int n,m,k,s,t;
void intt()
{
	clean(head,-1);
	clean(last,0);
	clean(pre,-1);
	ecnt=0;
	maxw=0,mincost=0;
}
void add(int u,int v,int w,int cost)
{
	edge[ecnt]=node(v,w,cost,head[u]);
	head[u]=ecnt++;
	edge[ecnt]=node(u,0,-cost,head[v]);
	head[v]=ecnt++;
}
/*---上面的是板子,不用动---*/

bool spfa()
{
	clean(dis,INF);
	clean(flow,INF);
	clean(vis,0);
	queue<int> que;
	que.push(s);
	vis[s]=1;
	dis[s]=0;
	pre[t]=-1;
	while(que.size())
	{
		int u=que.front();
		que.pop();
		vis[u]=0;
		for(int i=head[u];i+1;i=edge[i].nxt)
		{
			int temp=edge[i].v;
			if(dis[temp]>dis[u]+edge[i].cost&&edge[i].w>0)
			{
				dis[temp]=dis[u]+edge[i].cost;
				pre[temp]=u;
				last[temp]=i;
				flow[temp]=min(edge[i].w,flow[u]);
				if(vis[temp]==0)
				{
					vis[temp]=1;
					que.push(temp);
				}
			}
		}
	}
	return pre[t]!=-1;
}

void MCMF()
{
	while(spfa())
	{
		int u=t;
		maxw+=flow[t];//最大流 
		mincost+=dis[t]*flow[t];//最小费用 
		while(u!=s)
		{
			edge[last[u]].w-=flow[t];
			edge[last[u]^1].w+=flow[t];
			u=pre[u];
		}
	}
	//cout<<mincost<<endl;
	//cout<<maxw<<" "<<mincost<<endl;
}

int shop[55][55];//最多50个商店的50种需求 
int ware[55][55];//最多50个仓库的50种商品 
int cost[55][55][55];//50种商品别从50个仓库运送到50个商店的价格 
int rela[55][2];
int main()
{
	std::ios::sync_with_stdio(false);
	while(cin>>n>>m>>k&&n!=0)
	{
		int ans=0;
		clean(rela,0);
		clean(cost,0);
		clean(shop,0);
		clean(ware,0);
		for(int i=1;i<=n;++i)//第i个商店 
			for(int j=1;j<=k;++j)//第j种需求 
			{
				cin>>shop[i][j];
				rela[j][0]+=shop[i][j];
			}
		for(int i=1;i<=m;++i)//第i个仓库 
			for(int j=1;j<=k;++j)//第j种商品的 库存 
			{
				cin>>ware[i][j];
				rela[j][1]+=ware[i][j];
			}
		for(int i=1;i<=k;++i)//运送第i种货物
			for(int j=1;j<=n;++j)//运到第j个商店 
				for(int z=1;z<=m;++z)//从第z个仓库 
					cin>>cost[i][z][j];
		int f=0;
		for(int i=1;i<=k;++i)
			if(rela[i][0]>rela[i][1])//供不应求 
				f=1;
		if(f)
		{
			cout<<-1<<endl;
			continue;
		}
		for(int z=1;z<=k;++z)
		{
			intt();
			s=0,t=201;
			for(int i=1;i<=n;++i)//对于商店 
				add(s,i,shop[i][z],0);
			for(int i=1;i<=m;++i)//对于仓库 
				add(i+50,t,ware[i][z],0);
			for(int i=1;i<=n;++i)
			{
				for(int j=1;j<=m;++j)
				{
					add(i,j+50,INF,cost[z][j][i]);
				}
			}
			MCMF();
			if(maxw<rela[z][0])//只要有一个不符合要求,全部就都不符合要求 
			{
				cout<<-1<<endl;
				break;
			}
			ans+=mincost;
		}
		if(f==0)
			cout<<ans<<endl;
		/*for(int i=1;i<=n;++i)//50个商店 //为了避免你们不信,这是我第一次尝试的代码。。超时 
		{
			add(s,i,INF,0);//源 商店相连 
			for(int j=1;j<=k;++j)//每个商店对第j种的需求 
			{
				add(i,50+j,shop[i][j],0);
				for(int z=1;z<=m;++z)//从m个仓库 进货第k种 
				{
					if(ware[z][j]>0)//第z个仓库有j货物的库存 
						add(50+j,100+z,ware[z][j],cost[j][z][i]);
				}
			}
		}
		for(int i=1;i<=m;++i)//对于每一个仓库,与 汇相连,INF 
			add(i+100,t,INF,0);*/
//		for(int i=s;i<=t;++i)
//		{
//			cout<<i<<" : ";
//			for(int j=head[i];j+1;j=edge[j].nxt)
//				cout<<edge[j].v<<" "<<edge[j].w<<" "<<edge[j].cost<<" -->> ";
//			cout<<endl;
//		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/82015938