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

来源:互联网 发布:sql group by rollup 编辑:程序博客网 时间:2024/05/21 06:19
题意:有N个客户,M个仓库,和K种货物。已知每个客户需要每种货物的数量,每个仓库存储每种货物的数量,每个仓库运输各种货物去各个客户的单位费用。判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。

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

#include <iostream>using namespace std;#define N 155#define INF 999999int 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 999999int 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;}




 

原创粉丝点击