pku2516 最小费用最大流 SPFA+栈求最短路 Ford_Fulkerson思想

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;

}

你可能感兴趣的:(SPFA)