poj2516 Minimum Cost

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

题意:有N个shopkeeper(店主),M个supply places(供应点),每个供应点提供K种货物。

每个店主呢,对每种货物又有不同的数量需求。而每种货物从供应点运输到不同的店主时,所花费的费用也是不同的。

求在满足所有店主的需求的前提下,所需的最小花费;若不能满足,输出“-1”。

 

做了这个题我才知道,原来自己先前做的都只是最大流,这个才是真正的最小费用最大流(MCMF)啊。哎,恕我无知。

解题思路,copy网上的。K种货物独立来处理,也就是每一种货物都用MCMF来求一下最小费用。

构图:

建立超级源和超级汇,st,ed;

所有供应点与源点连边,容量为供应点的货物储存(只K种中的某一种,因为独立处理),费用为0;

所有店主与汇点连边,容量为店主所需的该种货物的数量,费用为0;

供应点与店主连边,容量为INF,费用为该种货物从该供应点运送至该店主时所需的费用。

 

#include<cstdio>
#include<cstring>
#include<queue>
#define MAXN 100
#define MAXE 10000
#define INF 0x7fffffff
#define MIN(a,b) a>b?b:a
using namespace std;
int shkp[MAXN][MAXN],supp[MAXN][MAXN],cost[MAXN][MAXN][MAXN];
int head[MAXN],dist[MAXN],vist[MAXN],pre[MAXN],pos[MAXN];
int cnt;
int n,m,k;
int st,ed;
int mincost,maxflow;
struct Edge
{
   int to;
   int cap;
   int cost;
   int next;
}edge[MAXE];

void add(int u,int v,int cap,int cost)
{
   edge[cnt].to=v;
   edge[cnt].cap=cap;
   edge[cnt].cost=cost;
   edge[cnt].next=head[u];
   head[u]=cnt++;
   
   edge[cnt].to=u;
   edge[cnt].cap=0;
   edge[cnt].cost=-cost;
   edge[cnt].next=head[v];
   head[v]=cnt++;
}

void MCMF(int st,int ed)
{
   int i,u,v;
   int aug;
   mincost=maxflow=0;
   for(;;)
   {
		memset(vist,0,sizeof(vist));
	   memset(pre,-1,sizeof(pre));
       //memset(dist,INF,sizeof(dist));
	   //memset赋值时,容易溢出变负数,一晚上错这里了!!!
	   for(i=0;i<=ed;i++)
		   dist[i]=INF;
       dist[st]=0;
       pre[st]=st;
       vist[st]=1;
	   queue<int> q;
       q.push(st);
       while(!q.empty())
       {
          u=q.front();
	      q.pop();
	      vist[u]=0;
	      for(i=head[u];i!=-1;i=edge[i].next)
	      {
		    v=edge[i].to;
		    if(edge[i].cap>0&&dist[v]>dist[u]+edge[i].cost)
		    {
		       dist[v]=dist[u]+edge[i].cost;
		       pre[v]=u;
		       pos[v]=i;
		       if(!vist[v])
			   {
				   vist[v]=1;
			       q.push(v);
			   }
			}
		  }
	   }
        //if(pre[ed]==-1)
	   if(dist[ed]==INF)  //这两个条件是等价的
			break;
		aug=INF;
		for(u=ed;u!=st;u=pre[u])
			aug=MIN(aug,edge[pos[u]].cap);
		maxflow+=aug;
		mincost+=dist[ed]*aug;
		for(u=ed;u!=st;u=pre[u])
		{
		   edge[pos[u]].cap-=aug;
		   edge[pos[u]^1].cap+=aug;
		}
   }
}

int main()
{
	int i,j,r;
	int need,totalcost,totalflow;
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		 if(!n&&!m&&!k)
		   return 0;
		need=0;
		totalcost=0;
		totalflow=0;
	   for(i=1;i<=n;i++)
		   for(j=1;j<=k;j++)
		   {
			   scanf("%d",&shkp[i][j]);
			   need+=shkp[i][j];
		   }
		for(i=1;i<=m;i++)
			for(j=1;j<=k;j++)
				scanf("%d",&supp[i][j]);
		for(r=1;r<=k;r++)
			for(i=1;i<=n;i++)
				for(j=1;j<=m;j++)
					scanf("%d",&cost[r][i][j]);
		for(r=1;r<=k;r++)
		{
		   cnt=0;
		   memset(head,-1,sizeof(head));
		   for(i=1;i<=m;i++)
			   add(0,i,supp[i][r],0);
		   for(i=1;i<=n;i++)
			   add(i+m,m+n+1,shkp[i][r],0);
		   for(i=1;i<=n;i++)
			   for(j=1;j<=m;j++)
				   add(j,i+m,INF,cost[r][i][j]);
			st=0;
			ed=n+m+1;
			MCMF(st,ed);
			totalcost+=mincost;
			totalflow+=maxflow;
		}
		if(totalflow!=need)
			totalcost=-1;
		printf("%d\n",totalcost);
	}
    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值