题解:因为 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; }