Sicily 1303 Job Assignment
题目链接: http://soj.sysu.edu.cn/1303
1303. Job Assignment
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
One problem comes up when we are trying to assign jobs about GDCPC’2003 (ZSUCPC’2003) to staffs. Because some of them complain that the tasks assigned to them are so bother. This emotion will lead to very bad effect in sequence. So we try to satisfy every staff as possible as we can. At first, we make an investigation to get the information about staffs’ attitude towards every task. And then we evaluate each attitude as a point (a positive integer number not larger than 100). The higher the point is, the more the staff is satisfied. Because the staffs are very busy, they have only a little leisure time to finish the task. So we just assign one task to one person, of course, one task can not be assigned to different persons. Now we give you all the points and hope you can help us to assign the tasks to make the sum of the points which correspond the assignment is maximum.
Input
Input will contain several test cases. The first line of each test case only contains one integer number N (0≤N≤100). N is the number of staffs, also is the number of tasks. And then, the following N lines describe staffs’ attitude. Each line contains n positive integer numbers. The jth number in the ith line describes ith staff‘s attitude to the jth task.
N=0 indicates the end of input file.
Output
For each test case you should output one line, and just one number in this line. The number is the maximum.
Sample Input
2 10 90 80 100 3 50 60 70 70 75 80 80 90 100 0
Sample Output
170 230
这里可以看出是一个二分图带权最大匹配的问题,KM算法我一直都理解不能,这里记一个模版以便以后使用。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <stack>
#include <cstring>
#include <vector>
#include <climits>
using namespace std;
const int MAX_N = 102;
const int _INF = INT_MAX / 2;
int Nx, Ny;//维度大小
int match[MAX_N];//Y的匹配 Y->X
int lx[MAX_N], ly[MAX_N];//顶标
int slack[MAX_N];//寻找不到的情况下暂存差值的最小值
int weight[MAX_N][MAX_N];//路径长
bool visx[MAX_N], visy[MAX_N];//标记访问到
bool dfs(int x) {
visx[x] = true;
for (int y = 0; y < Ny; ++y) {
if (visy[y])
continue;
int gap = lx[x] + ly[y] - weight[x][y];
if (gap == 0) {
visy[y] = true;
if (match[y] == -1 || dfs(match[y])) {
match[y] = x;
return true;
}
}
else slack[y] = min(gap, slack[y]);
}
return false;
}
int KM(void) {
//初始化ly,match
memset(ly, 0, sizeof(ly));
for (int i = 0; i < MAX_N; ++i) {
match[i] = -1;
}
//初始化lx为边权重最大的
for (int i = 0; i < Nx; ++i) {
lx[i] = weight[i][0];
for (int j = 1; j < Ny; ++j)
if (lx[i] < weight[i][j])
lx[i] = weight[i][j];
}
for (int x = 0; x < Nx; ++x) {
for (int y = 0; y < Ny; ++y)
slack[y] = _INF;
for (;;) {
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
//如果找到增广路
if (dfs(x))
break;
//未找到时修改条件
int d = _INF;
for (int y = 0; y < Ny; ++y) {
if (visy[y] == false && d > slack[y])
d = slack[y];
}
for (int i = 0; i < Nx; ++i) {
if (visx[i])
lx[i] -= d;
}
for (int y = 0; y < Ny; ++y) {
if (visy[y])
ly[y] += d;
else
slack[y] -= d;
}
}
}
int res = 0;
for (int i = 0; i < Ny; ++i) {
if (match[i] != -1)
res += weight[match[i]][i];
}
return res;
}
KM算法的主体部分已经出来了,
剩下部分调用即可
int main() {
int N;
while (cin >> N && N) {
Nx = Ny = N;
for (int x = 0; x < Nx; ++x) {
for (int y = 0; y < Ny; ++y) {
scanf("%d", &weight[x][y]);
}
}
printf("%d\n", KM());
}
return 0;
}