Description
You were just hired as CEO of the local junkyard.One of your jobs is dealing with the incoming trash and sorting it for recycling.The trash comes every day in
N containers and each of these containers contains certain amount of each of the
N types of trash. Given the amount of trash in the containers find the optimal way to sort the trash. Sorting the trash means putting every type of trash in separate container. Each of the given containers has infinite capacity. The effort for moving one unit of trash from container
i to
j is 1 if
i ≠
j otherwise it is 0.You are to minimize the total effort.
Input
The first line contains the number
N (1 ≤
N ≤ 150), the rest of the input contains the descriptions of the containers.The (1 +
i)-th line contains the description of the
i-th container the
j-th amount (0 ≤ amount ≤ 100) on this line denotes the amount of the
j-th type of trash in the
i-th container.
Output
You should write the minimal effort that is required for sorting the trash.
Sample Input
input | output |
---|---|
4 62 41 86 94 73 58 11 12 69 93 89 88 81 40 69 13 | 650 |
/*
KM 算法复杂度O(V^3)
左边N 个点0..N-1 右边M 个点0..M-1 求匹配要保证N <=
M(swap(N,M))否则循环无法终止
mat[i][j]表示i 和j 之间有边,
lx[],ly[]是X,Y 上各点的标号
linky[y] = x 代表y 被x 匹配未匹配点linky[] = -1
最小权匹配可将权值取相反数或用一个大数去减
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 502;
const int MAXV = 0x3F3F3F3F;
int mat[MAXN][MAXN];
bool visitx[MAXN],visity[MAXN];
int lx[MAXN],ly[MAXN],linky[MAXN];
int N,M,slack[MAXN];
int find(int u) {
visitx[u] = 1;
for (int i = 0;i < M;i++) {
if (!visity[i]) {
int tmp = lx[u] + ly[i] - mat[u][i];
if (tmp == 0) {
visity[i] = 1;
if (linky[i] == -1 || find(linky[i])) {
linky[i] = u;
return 1;
}
}
else if (tmp < slack[i])
slack[i] = tmp;
}
}
return 0;
}
int KM() {
for (int i = 0;i < N;i++) {
lx[i] = 0;
for (int j = 0;j < M;j++)
if (mat[i][j] > lx[i])
lx[i] = mat[i][j];
}
for (int j = 0;j < M;j++)
ly[j] = 0;
memset(linky,-1,sizeof(linky));
for (int i = 0;i < N;i++) {
for (int j = 0;j < M;j++)
slack[j] = MAXV;
while (1) {
memset(visitx,0,sizeof(visitx));
memset(visity,0,sizeof(visity));
int min = MAXV;
if (find(i)) break;
for (int j = 0;j < M;j++)
if (!visity[j] && slack[j] < min)
min = slack[j];
for (int j = 0;j < N;j++)
if (visitx[j])
lx[j] -= min;
for (int j = 0;j < M;j++)
if (visity[j])
ly[j] += min;
else
slack[j] -= min;
}
}
int ret = 0,cnt = 0;
for (int i = 0;i < M;i++) {
int v = linky[i];
if (v >= 0&& mat[v][i] != -MAXV) {
cnt++;
ret += mat[v][i];
}
}
if (cnt < N) //不存在最佳匹配
return -1;
else
return ret;
}
int main() {
while (~scanf("%d",&N)) {
M = N;
int sum = 0;
for (int i = 0;i < N;i++)
for (int j = 0;j < M;j++)
{
scanf("%d",&mat[i][j]);
sum += mat[i][j];
}
int ans = sum - KM();
printf("%d\n",ans);
}
return 0;
}