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;
}
题解:因为 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; }
相关文章推荐
- (最小费用最大流)POJ2516 Minimum Cost
- poj 2516 Minimum Cost(最小费用最大流 spfa算法求最短路)
- poj 2516 Minimum Cost(最小费用最大流)
- POJ - 2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost (最小费用最大流)
- poj_2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost 最小费用最大流
- POJ 2516 Minimum Cost 【MCMF:最小费用最大流】
- POJ--2516 - Minimum Cost(最小费用最大流)
- poj 2516 Minimum Cost(最小费用最大流)
- poj 2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost (最小费用最大流)
- poj 2516 Minimum Cost 最小费用最大流
- poj-2516-Minimum Cost-最小费用最大流
- POJ 2516 Minimum Cost(最小费用最大流)
- POJ 2516 Minimum Cost (最小费用最大流)
- POJ 2516 Minimum Cost(最小费用最大流啊)