现在的位置: 首页 > 综合 > 正文

POJ 2516 Minimum Cost (最小费用最大流,KM解法)

2013年08月03日 ⁄ 综合 ⁄ 共 3501字 ⁄ 字号 评论关闭

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

题解:因为 K 种产品互相不干扰,所以关键是把 K 种产品分开求解。给出了两种slack方式。

#include <iostream>
using namespace std;

#define N 155
#define INF 999999

int need[N][N], store[N][N], cost[N][N][N];
int A[N], B[N], visA[N], visB[N];
int match[N], fee[N][N], slack;
int n, m, kind, X, Y;

bool find_path ( int i )
{
	visA[i] = 1;
	for ( int j = 1; j <= Y; j++ )
	{
		if ( visB[j] ) continue;
		int temp = fee[i][j] - (A[i] + B[j]);
		if ( temp == 0 )
		{
			visB[j] = 1;
			if ( ! match[j] || find_path(match[j]) )
			{
				match[j] = i;
				return true;
			}
		}
		else if ( slack > temp )
			slack = temp;
	}
	return false;
}

void KM()
{
	int i, j;
	memset(B,0,sizeof(B));
	memset(match,0,sizeof(match));

	for ( i = 1; i <= X; i++ )
	{
		A[i] = INF;
		for ( j = 1; j <= Y; j++ )
			if ( A[i] > fee[i][j] )
				A[i] = fee[i][j];
	}

	for ( i = 1; i <= X; i++ )
	{
		while ( 1 )
		{
			slack = INF;
			memset(visA,0,sizeof(visA));
			memset(visB,0,sizeof(visB));
			if ( find_path ( i ) ) break;
/*注意!:A中位于交错树中的点加上slack,B中位于交错树中的点减去slack,若反过来则TLE*/
			for ( j = 1; j <= X; j++ )
				if ( visA[j] ) A[j] += slack;
			for ( j = 1; j <= Y; j++ )
				if ( visB[j] ) B[j] -= slack;
		}
	}
}

int solve()
{
	int i, j, k, ans = 0;
	for ( k = 1; k <= kind; k++ )
	{
		X = Y = 0;
		for ( i = 1; i <= n; i++ )
			for ( j = 1; j <= need[i][k]; j++ )
				A[++X] = i;
			
		for ( i = 1; i <= m; i++ )
			for ( j = 1; j <= store[i][k]; j++ )
				B[++Y] = i;
				
		memset(fee,0,sizeof(fee));
		for ( i = 1; i <= X; i++ )
			for ( j = 1; j <= Y; j++ )
				fee[i][j] = cost[k][A[i]][B[j]];
					
		KM();
		for ( i = 1; i <= Y; i++ )
			ans += fee[match[i]][i];
	}
	return ans;
}

int main()
{
	while ( scanf("%d%d%d",&n,&m,&kind) )
	{
		if ( !n && !m && !kind ) break;

		int i, j, k;
		for ( i = 1; i <= n; i++ )
			for ( j = 1; j <= kind; j++ )
				scanf("%d",&need[i][j]);

		for ( i = 1; i <= m; i++ )
			for ( j = 1; j <= kind; j++ )
				scanf("%d",&store[i][j]);

		for ( k = 1; k <= kind; k++ )
			for ( i = 1; i <= n; i++ )
				for ( j = 1; j <= m; j++ )
					scanf("%d",&cost[k][i][j]);

		for ( k = 1; k <= kind; k++ )
		{
			int totalNeed = 0;
			int totalStore = 0;
			for ( i = 1; i <= n; i++ )
				totalNeed += need[i][k];
			for ( i = 1; i <= m; i++ )
				totalStore += store[i][k];

			if ( totalStore < totalNeed )
			{
				printf("-1\n");
				goto next;
			}
		}
		printf("%d\n",solve());
next:;
	}
	return 0;
}

 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define N 155
#define INF 999999

int need[N][N], store[N][N], cost[N][N][N];
int A[N], B[N], visA[N], visB[N];
int match[N], fee[N][N], slack[N];
int n, m, kind, X, Y;

bool find_path ( int i )
{
	visA[i] = 1;
	for ( int j = 1; j <= Y; j++ )
	{
		if ( visB[j] ) continue;
		if ( fee[i][j] == A[i] + B[j] )
		{
			visB[j] = 1;
			if ( -1 == match[j] || find_path(match[j]) )
			{
				match[j] = i;
				return true;
			}
		}
		else if ( slack[j] > A[i] + B[j] - fee[i][j] )
			slack[j] = A[i] + B[j] - fee[i][j];
	}
	return false;
}

void KM()
{
	int i, j, d;
	memset(B,0,sizeof(B));
	memset(match,-1,sizeof(match));
	for ( i = 1; i <= X; i++ )
		for (A[i] = -INF, j = 1; j <= Y; j++ )
            if ( A[i] < fee[i][j] )
                A[i] = fee[i][j];
	for ( i = 1; i <= X; i++ )
	{
	    for ( j = 1; j <= Y; j++ )
            slack[j] = INF;
		while ( 1 )
		{
			memset(visA,0,sizeof(visA));
			memset(visB,0,sizeof(visB));
			if ( find_path ( i ) ) break;
            for ( d = INF, j = 1; j <= Y; j++ )
                if ( !visB[j] && d > slack[j] ) d = slack[j];
			for ( j = 1; j <= X; j++ )
				if ( visA[j] ) A[j] -= d;
			for ( j = 1; j <= Y; j++ )
				if ( visB[j] ) B[j] += d;
                else slack[j] -= d;
		}
	}
}

int solve()
{
	int i, j, k, ans = 0;
	for ( k = 1; k <= kind; k++ )
	{
		X = Y = 0;
		for ( i = 1; i <= n; i++ )
			for ( j = 1; j <= need[i][k]; j++ )
				A[++X] = i;
		for ( i = 1; i <= m; i++ )
			for ( j = 1; j <= store[i][k]; j++ )
				B[++Y] = i;
		memset(fee,0,sizeof(fee));
		for ( i = 1; i <= X; i++ )
			for ( j = 1; j <= Y; j++ )
				fee[i][j] = -cost[k][A[i]][B[j]];
		KM();
		for ( i = 1; i <= Y; i++ )
            if ( match[i] != -1 ) //注意,match[i]必须在已经匹配的情况下才能相加
			    ans += fee[match[i]][i];
	}
	return -ans;
}

int main()
{
	while ( scanf("%d%d%d",&n,&m,&kind) )
	{
		if ( !n && !m && !kind ) break;

		int i, j, k;
		for ( i = 1; i <= n; i++ )
			for ( j = 1; j <= kind; j++ )
				scanf("%d",&need[i][j]);

		for ( i = 1; i <= m; i++ )
			for ( j = 1; j <= kind; j++ )
				scanf("%d",&store[i][j]);

		for ( k = 1; k <= kind; k++ )
			for ( i = 1; i <= n; i++ )
				for ( j = 1; j <= m; j++ )
					scanf("%d",&cost[k][i][j]);

		for ( k = 1; k <= kind; k++ )
		{
			int totalNeed = 0;
			int totalStore = 0;
			for ( i = 1; i <= n; i++ )
				totalNeed += need[i][k];
			for ( i = 1; i <= m; i++ )
				totalStore += store[i][k];

			if ( totalStore < totalNeed )
			{
				printf("-1\n");
				goto next;
			}
		}
		printf("%d\n",solve());
next:;
	}
	return 0;
}

 

抱歉!评论已关闭.