您的位置:首页 > 其它

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

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

题解:因为 K 种产品互相不干扰,所以关键是把 K 种产品分开求解。给出了两种slack方式。
#include <iostream>
using namespace std;

#define N 155
#define INF 999999

int need

, store

, cost

;
int A
, B
, visA
, visB
;
int match
, fee

, 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

, store

, cost

;
int A
, B
, visA
, visB
;
int match
, fee

, 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;
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;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  path 产品 存储