poj 2516 (多次费用流)

题意:有N个客户,M个仓库,和K种货物。已知每个客户需要每种货物的数量,每个仓库存储每种货物的数量,每个仓库运输各种货物去各个客户的单位费用。判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。


最小费用最大流。先判断是否每种货物的存储总量都足够,足够的话,对每一种货物进行一次最小费用最大流求出完成这种货物运输的最小总费用,所有的总费用相加就是结果了


#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=100 ;
const int M=80000 ;
const int inf=1<<30 ;
struct node
{
	int u,v,c,cost,next;
}edge[M] ; 
int head[N],dist[N],pre[N],pp[N],vist[N];
int need[N][N],stroe[N][N],Need[N],Stroe[N] ;
int top;

void add(int u ,int v,int c,int cost)      
{      
    edge[top].u=u;      
    edge[top].v=v;      
    edge[top].c=c;      
    edge[top].cost=cost;      
    edge[top].next=head[u];      
    head[u]=top++;      
    edge[top].u=v;      
    edge[top].v=u;      
    edge[top].c=0;      
    edge[top].cost=-cost;      
    edge[top].next=head[v];      
    head[v]=top++;      
}      
      
int SPFA(int s,int t)      
{      
    int u , v ;      
    memset(vist,0,sizeof(vist));      
    memset(pre,-1,sizeof(pre));      
    for(int i = 0 ; i <= t ; i++)  dist[i]=inf ;      
    vist[s]=1;dist[s]=0;pre[s]=s;      
    queue<int>q;      
    q.push(s);      
    while(!q.empty())      
    {      
         u=q.front();      
         q.pop();      
         vist[u]=0;      
         for(int i =head[u];i!=-1;i=edge[i].next)      
         {      
               v=edge[i].v;      
               if(edge[i].c && dist[v] > dist[u]+edge[i].cost)      
               {      
                    dist[v] = dist[u]+edge[i].cost ;      
                     pre[v]=u;      
                     pp[v]=i;      
                     if(!vist[v]);      
                     {      
                           vist[v]=1;      
                           q.push(v);      
                     }      
               }      
        }      
    }      
    if(dist[t]==inf) return 0;      
    return 1 ;      
}      
      
int MFMC(int s,int t)      
{      
    int mincost=0,flow=0,minflow ;      
    while(SPFA(s,t))      
    {      
          minflow=inf;      
          for(int i=t;i!=s;i=pre[i])      
              minflow=min(minflow,edge[pp[i]].c);      
          for(int i=t;i!=s;i=pre[i])      
          {      
                edge[pp[i]].c -= minflow;      
                edge[pp[i]^1].c += minflow;      
          }          
          flow += minflow;      
          mincost += dist[t]*minflow ;      
        //  printf("****");  
    }      
    return mincost ;      
}      


int main()
{
	  int n,m,K,k ,w;
	  while(~scanf("%d%d%d",&n,&m,&K))
	  {  
	    if( (n+m+K)==0)  break;
	  	  memset(Need,0,sizeof(Need)) ;
	  	  memset(Stroe,0,sizeof(Stroe)) ;
	  	      for(int i = 1 ; i <= n ;i++)
	  	         for(int j = 1 ; j <=K; j++) 
				 {
	  	       	     scanf("%d",&need[i][j]) ;  //i客户需要j货物的数量 
					 Need[j] += need[i][j] ;	//客户需要j货物的总数量   
	  	         } 
	          for(int i = 1 ; i <= m ; i++)
			    for(int j = 1 ; j <= K; j++)	
	  	          {
	  	          	   scanf("%d",&stroe[i][j]) ;//i仓库储存j货物的数量 
	  	          	    Stroe[j] += stroe[i][j] ;  //仓库储存j货物的总数量   
	  	          } 
	  	         int flag = 0 ;   //判断是否有解 
				 for(int i = 1 ; i <= K ; i++)
				   if(Need[i]  > Stroe[i])//无解 
				     {
				     	 flag=1; break;
				     }  
			 int ans = 0 ,s=0,t=n+m+1;	     
	  	     for(int k = 1 ; k <= K ; k++)//K种物品,K次建图 
	  	     {
	  	     	      top =0;
	  	             memset(head,-1,sizeof(head));
	  	     	     for(int i = 1 ; i <= n ; i++)
	  	     	       for(int j = 1 ; j <= m ; j++)
	  	     	         {
	  	     	         	    scanf("%d",&w) ; //j仓库到i客户的单位花费 
	  	     	         	    add(j,m+i,inf,w);//连边 
	  	     	         }
	  	     	        if(flag) continue ; //无解,不用继续下去 
	  	     	       for(int i = 1 ; i <= m ;i++)	  	     	       
	  	     	       	     add(s,i,stroe[i][k] ,0) ;
	  	     	       for(int i = 1 ; i <= n ; i++)
	  	     	            add(m+i,t,need[i][k],0) ; 
	  	     	    ans += MFMC(s,t) ;//对k物品跑一次费用流 
	  	     	     
	  	     } 
	  	  if(flag)  printf("-1\n") ;
	  	  else      printf("%d\n",ans) ;
	  }
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值