poj-2516-Minimum Cost-最小费用最大流

本文详细介绍了一种基于SPFA算法解决最小费用流问题的方法,包括算法实现细节、关键步骤及注意事项。通过具体实例展示了如何利用SPFA算法进行最优路径搜索,并解决了商品供应与需求匹配的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题目分别求每一商品的最小费用,然后加起来就可以了。

但是调试了很久,郁闷,好多地方写的不对。也许是自己没看模版的原因。

记住:

1,反向边初始化为0;

2,spfa的标记。

3,初始化。


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
#define INF 999999
int need[101][101];//i商店需要j的数量
int give[101][101];//i供货商给出j的数量
int fei[101][101][101];//j供货商给i商店k的费用
int cost[101][101];
struct list 
{
	int u;
	int v;
	int next;
}node[100001];
int nos;
int num;
int head[105];
void add(int l,int r ,int v)
{
	node[num].u=r;
	node[num].v=v;
	node[num].next=head[l];
	head[l]=num++;
}
int pre[105];
int spfa()
{
	int visit[105];
	int dist[105];
	int i;
	for(i=0;i<=nos;i++)dist[i]=INF;
	memset(visit,0,sizeof(visit));
	memset(pre,-1,sizeof(pre));
	queue<int >q;
	q.push(0);
	dist[0]=0;
	visit[0]=1;
	while(!q.empty())
	{
		int e=q.front();
		q.pop();
		visit[e]=0;
		for(i=head[e];i!=-1;i=node[i].next)
		{
			int r=node[i].u;
			if(dist[r]>dist[e]+node[i].v&&cost[e][r])
			{
				pre[r]=e;
				dist[r]=dist[e]+node[i].v;
				if(!visit[r])
				{
					q.push(r);
					visit[r]=1;
				}
			}
		}
	}
	if(dist[nos]==INF)return 0;
	else return 1;
}
void change()
{
	int minx,i;
	minx=INF;
	for(i=nos;pre[i]!=-1;i=pre[i])
	{
		minx=min(minx,cost[pre[i]][i]);
	}
	for(i=nos;pre[i]!=-1;i=pre[i])
	{
		cost[pre[i]][i]-=minx;
		cost[i][pre[i]]+=minx;
	}
}	
int main()
{
	int N,M,K,i,j,k;
	while(scanf("%d%d%d",&N,&M,&K)&&(N||M||K))
	{
		for(i=1;i<=N;i++)
			for(j=1;j<=K;j++)
				scanf("%d",&need[i][j]);
				
		for(i=1;i<=M;i++)
			for(j=1;j<=K;j++)
				scanf("%d",&give[i][j]);
				
		for(k=1;k<=K;k++)
			for(i=1;i<=N;i++)
				for(j=1;j<=M;j++)
					scanf("%d",&fei[i][j][k]);
					
		for(k=1;k<=K;k++)
		{
			int n1,n2;
			n1=n2=0;
			for(i=1;i<=N;i++)n1+=need[i][k];
			for(i=1;i<=M;i++)n2+=give[i][k];
			if(n1>n2)break;
		}	
		if(k!=K+1)
		{
			printf("-1\n");
			continue;
		}
		int sumuse;
		sumuse=0;
		nos=N+M+1;
		for(k=1;k<=K;k++)
		{
			num=0;
			memset(cost,0,sizeof(cost));
			memset(head,-1,sizeof(head));
			for(j=1;j<=M;j++)
			{
				add(0,j,0);
				add(j,0,0);
				cost[0][j]=give[j][k];
				cost[j][0]=0;
			}
			for(i=1;i<=N;i++)
			{
				add(i+M,nos,0);
				add(nos,i+M,0);
				cost[i+M][nos]=need[i][k];
				cost[nos][i+M]=0;
			}
			for(i=1;i<=N;i++)
			{
				for(j=1;j<=M;j++)
				{
					add(j,i+M,fei[i][j][k]);
					add(i+M,j,-fei[i][j][k]);
					cost[j][i+M]=INF;
					cost[i+M][j]=0;
				}
			}
			while(spfa())
			{
				change();
			}
			for(j=1;j<=M;j++)
			{
				for(i=1;i<=N;i++)
				{
					sumuse+=fei[i][j][k]*(INF-cost[j][i+M]);
				}
			}
		}
		printf("%d\n",sumuse);
	}
	return 0;
}
		
				
				
				
				
				
				
				
				
				
				
				
				
				
				




                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值