Minimum Cost

最近在看最小费用最大流,找了道题,练了练,还是比较简单的。

题意很明确,有N个店主和M个供应商,有K种商品,每个店主对每个商品的需求量不一样,每个供应商对每个商品的库存量也不同,每种商品有不同的供应商提供给不同的店主,价格也不一样,都已给出,求满足店主所有要求的最小花费。由于各个商品互不干扰,就对每种商品求一次最小费用最大流就行了。建一个源点S = 0, 汇点T = N + M +1

一共有三类边:

1.S到供应商的边 供应商编号1到M,花费为0, 容量为库存的数量

2.供应商到店主的边 店主编号M + 1到M + N,花费为读入,容量为INF

3.店主到T的边 花费为0,容量为读入需要的数量

#include<stdio.h>
#define INF 0xfffffff

int N, M, K, S, T;
int cost[54][54][54]; // cost[k][i][j] 第k种商品从第j个供应商送给第i个店主需要的花费 
int have[54][54];     // have[i][k] 第i个供应商拥有第k种商品的数量 
int need[54][54];     // need[i][k] 第i个店主需要的第k种商品的数量 
int b[104][104];      // b[i][j]  节点i 到 节点j的 距离(商品运输的单位花费) 
int f[104][104];      // f[i][j]  边<i, j>的剩余容量 
int dis[104];         // dis[i] 保存i节点到源点S 的最小距离 
int mark[104];        // 求最短路时的标记数组 
int stack[104];       // 用栈 + SPFA 来实现最短路 
int pre[104];         // 记录最短路 路径 

int Min(int a, int b){
    return a < b ? a : b;     
}
int Spfa()// 求最短路
{
	int i, u, v, top;
	for (i = S; i <= T; i++){
		dis[i] = INF;
		mark[i] = 0;
	}
	mark[S] = 1;
	dis[S] = 0;
	top = 0;
	stack[++top] = S;
	
	while(top){
		u = stack[top--];
		mark[u] = 0;
		for (v = 0; v <= N + M + 1; v++){
			if (f[u][v] && dis[v] > dis[u] + b[u][v]){
				dis[v] = dis[u] + b[u][v];
				pre[v] = u; // 每一次的更新都需要改变前继节点的指向,无论是否要入栈 
				if (!mark[v]){
                    stack[++top] = v;
                    mark[v] = 1;
				}
			}
		}
	}
	return dis[T];
}
int MinCostMaxFlow()
{
	int i, t, minf, c;
	int ans = 0;
	int maxFlow = 0;
	while((c = Spfa()) != INF){
		minf = INF;
		t = T;
		while(t != S){
            minf = Min(minf, f[pre[t]][t]);
            t = pre[t];
		}
		maxFlow += minf;
		t = T;
		while(t != S){
			f[pre[t]][t] -= minf;
			f[t][pre[t]] += minf;
			b[t][pre[t]] = - b[pre[t]][t];
			t = pre[t];
		}
		ans += c * minf;
	}
	for (i = 1; i <= N; i++){
		if (f[i + M][T]) break;
	}
	return (i <= N ? 0 : ans);
}

void Read()//读入数据
{
	int i, j, 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", &have[i][j]);
		}
	}
	
	for (k = 1; k <= K; k++){
		for (i = 1; i <= N; i++){
			for (j = 1; j <= M; j++){
				scanf("%d", &cost[k][i][j]);    
			}
		}
	}
}

void CreatGraph(int k) // 建图
{
	int i, j; 
	for (i = S; i <= T; i++){
		for (j = S; j <= T; j++){
			b[i][j] = INF;
			f[i][j] = 0;
		}
	}
	
	for (i = 1; i <= M; i++){
		b[S][i] = 0;
	//	b[i][S] = INF;
		f[S][i] = have[i][k];
	//	f[i][S] = 0;
		
		for (j = 1; j <= N; j++){
			b[i][j + M] = cost[k][j][i];
		//	b[j + M][i] = INF;
			f[i][j + M] = INF;
	//		f[j + M][i] = 0;
		}
	}
	for (i = 1; i <= N; i++){
		b[i + M][T] = 0;
	//	b[T][i + M] = INF;
		f[i + M][T] = need[i][k];
	//	f[T][i + M] = 0;
	}
}
int main()
{
    int k, t, ans;
    while (scanf("%d%d%d", &N, &M, &K) != EOF){
		if (N == 0 && M == 0 && K == 0) break;
		Read();
		S = 0;  // 源点
		T = M + N + 1; // 汇点
		ans = 0;
		for (k = 1; k <= K; k++){
            CreatGraph(k);
			t = MinCostMaxFlow();
			if (!t) break;
			ans += t;
		}
		if (k <= K) puts("-1");
		else printf("%d\n", ans);
    }
    return 0;
}
posted on 2010-08-02 21:29  ylfdrib  阅读(609)  评论(0编辑  收藏  举报