1 /*
2 KM:裸题第一道,好像就是hungary的升级版,不好理解,写点注释
3 KM算法用来解决最大权匹配问题: 在一个二分图内,左顶点为X,右顶点为Y,现对于每组左右连接Xi,Yj有权w(i,j),
4 求一种匹配使得所有w(i,j)的和最大。也就是最大权匹配一定是完备匹配。如果两边的点数相等则是完美匹配。
5 如果点数不相等,其实可以虚拟一些点,使得点数相等,也成为了完美匹配。最大权匹配还可以用最大流去解决
6 */
7 #include <cstdio>
8 #include <algorithm>
9 #include <cstring>
10 using namespace std;
11
12 const int MAXN = 3e2 + 10;
13 const int INF = 0x3f3f3f3f;
14 int x[MAXN], y[MAXN], w[MAXN][MAXN];
15 int lx[MAXN], ly[MAXN];
16 bool visx[MAXN], visy[MAXN];
17 int n, d;
18
19 bool DFS(int u) { //hungary算法
20 visx[u] = true;
21 for (int i=1; i<=n; ++i) {
22 if (x[u] + y[i] == w[u][i] && !visy[i]) {
23 visy[i] = true;
24 if (ly[i] == -1 || DFS (ly[i])) {
25 ly[i] = u; return true;
26 }
27 }
28 else if (x[u] + y[i] > w[u][i]) d = min (d, x[u] + y[i] - w[u][i]); //更新d,贪心思想
29 }
30
31 return false;
32 }
33
34 void KM(void) {
35 for (int i=1; i<=n; ++i) {
36 x[i] = 0;
37 for (int j=1; j<=n; ++j) {
38 x[i] = max (x[i], w[i][j]); //初始x标杆为最大值w,y为0
39 }
40 }
41
42 memset (y, 0, sizeof (y));
43 memset (ly, -1, sizeof (ly));
44 for (int i=1; i<=n; ++i) {
45 while (true) {
46 memset (visx, false, sizeof (visx));
47 memset (visy, false, sizeof (visy));
48 d = INF;
49 if (DFS (i)) break; //找到增广轨,退出
50 for (int i=1; i<=n; ++i) { //没有找到,对标杆进行调整
51 if (visx[i]) x[i] -= d;
52 if (visy[i]) y[i] += d;
53 }
54 }
55 }
56
57 int res = 0;
58 for (int i=1; i<=n; ++i) {
59 res += x[i] + y[i];
60 }
61 printf ("%d\n", res);
62 }
63
64 int main(void) { //HDOJ 2255 奔小康赚大钱
65 //freopen ("HDOJ_2255.in", "r", stdin);
66
67 while (scanf ("%d", &n) == 1) {
68 for (int i=1; i<=n; ++i) {
69 for (int j=1; j<=n; ++j) {
70 scanf ("%d", &w[i][j]);
71 }
72 }
73 KM ();
74 }
75
76 return 0;
77 }