poj2516 最小费用最大流

 
第一次见到这样的题,真的是看别人的思想然后看别人的代码了一晚上,先明白别人的代码的意思,但是不懂为什么那么写,然后画个图忽然就明白了,下面就是根据这道题最初最小费用最大流的分析!

题目大意:给出n个客户对k个商品的需求量,又给出m个仓库对k个物品的存货量以及对k个物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费,是典型的最小费用最大流!

题目解析:可以将k中物品分开求最小然后想加!

建图,对每个仓库是一个结点,每个客户也是一个结点,除此之外再加上s源点和t结束点!

1、s到仓库i的边的权值为仓库i的供给量

2、仓库i到客户j的权值为仓库的供给量

3、客户j到t的权值为客户的需求量

4、还有建立花费图,cost[i][j]代表仓库i到客户j的没一个物品的运费

然后用spfa算法求s到t的最小路径(路径上边的权值不为0),如果到t的最短路径有更新(此条路径话费最少),则记录这条路径,求出这条路径上权值最小的边的权值,然后这条路径上所有的边的权值都减去该边的权值min,此时最小的花费增加了min*在这条边上的花费!如果s到t的值没有更新,则对于k物品的最小花费则已经求出来了!

表达能力不强,脑袋清楚说不出来,下面是代码,如果实在不明白的话就好好看看代码哈!

 

#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
#define min(a,b) (a)<(b)?(a):(b)
#define N 130
#define inf 100000000
int need[N][N];
int offer[N][N];
int map[N][N],cost[N][N];
int sum_need[N],sum_offer[N];
int n,m,K;
int pre[N];
int s,t;//源点和结束点
int spfa()
{
	int dis[N];
	bool vis[N];
	int i;
	queue<int>q;
	for(i=0; i<=t; i++)
	{
		vis[i]=false;
		dis[i]=inf;
	}
	vis[s]=true;
	dis[s]=0;
	q.push(s);
	while(!q.empty())
	{
		int k=q.front();
		vis[k]=false;
		q.pop();
		for(i=0; i<=t; i++)
		{
	
			if(map[k][i] && dis[i]>dis[k]+cost[k][i])
			{
				dis[i]=dis[k]+cost[k][i];
				pre[i]=k;
				if(vis[i]==false)
				{
					vis[i]=true;
					q.push(i);
				}
			}
		}
	}
	if(dis[t]!=inf)
		return 1;
	else
		return 0;
}
int fond()
{
	int i,j;
	int Min=INT_MAX;
	j=0;
	while(spfa())
	{
		for(i=t;i!=s; i=pre[i])
			Min=min(Min,map[pre[i]][i]);
		for(i=t; i!=s; i=pre[i])
		{
			map[pre[i]][i]-=Min;
			map[i][pre[i]]+=Min;
			j+=cost[pre[i]][i]*Min;
		}
	}
	return j;
}
int main()
{
	int i,j,k,sum,sign;
	while(scanf("%d%d%d",&n,&m,&K))
	{
		if(n==0 && m==0 && K==0)
			break;
		sum=0;
		memset(sum_need,0,sizeof(sum_need));
		memset(sum_offer,0,sizeof(sum_offer));
		for(i=1; i<=n; i++)
			for(j=1; j<=K; j++)
			{
				scanf("%d",&need[i][j]);
                sum_need[j]+=need[i][j];
			}
         for(i=1; i<=m; i++)
		   for(j=1; j<=K; j++)
		   {
			   scanf("%d",&offer[i][j]);
			   sum_offer[j]+=offer[i][j];
		   }
		sign=0;
		for(i=1; i<=K; i++)
			if(sum_offer[i]<sum_need[i])
			{
				sign=1;
				break;
			} 
		s=0;
		t=m+n+1; 
		for(k=1; k<=K; k++)
		{
			for(i=0; i<=t; i++)
				for(j=0; j<=t; j++)
					map[i][j]=cost[i][j]=0;
			for(i=1+m; i<=n+m; i++)
				for(j=1; j<=m; j++)
				{
					scanf("%d",&cost[j][i]);
					cost[i][j]=-cost[j][i];
				} 
		    if(sign==1)
			   continue;  
		    for(i=1; i<=m; i++)
			   map[s][i]=offer[i][k];
	    	for(i=1; i<=m; i++)
			   for(j=1+m; j<=n+m; j++)
				 map[i][j]=offer[i][k];  
		   for(i=m+1; i<=m+n; i++)
		    	map[i][t]=need[i-m][k];
		  sum+=fond();
		}
	if(sign==1)
		printf("-1\n");
	else
		printf("%d\n",sum);
	}
	
    return 0;
}


 

你可能感兴趣的:(poj2516 最小费用最大流)