題意:有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;}