- 最大权二分匹配
- 最小权二分匹配 (建边时,把边改成负的)
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 505;
const int INF = 0x3f3f3f3f;
int G[maxn + 5][maxn + 5];
int ex_X[maxn], ex_Y[maxn];
bool vis_X[maxn], vis_Y[maxn];
int Slack[maxn + 5];
int Match[maxn + 5];
int N;
bool Dfs(int x){
vis_X[x] = 1;
for(int i = 1; i <= N; ++i){
if(vis_Y[i]) continue;
int tmp = ex_X[x] + ex_Y[i] - G[x][i];
if(tmp != 0){
Slack[i] = min (Slack[i], tmp);
} else {
vis_Y[i] = 1;
if (Match[i] == -1 || Dfs(Match[i])) {
Match[i] = x;
return true;
}
}
}
return false;
}
/*
2
100 10
15 23
*/
int KM(){
memset(Match, -1, sizeof(Match));
memset(ex_X, 0, sizeof(ex_X));
memset(ex_Y, 0, sizeof(ex_Y));
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
ex_X[i] = max(ex_X[i], G[i][j]);
}
}
for (int i = 1; i <= N; ++i) {
memset(Slack, INF, sizeof Slack);
while(1){
memset(vis_X, 0, sizeof(vis_X));
memset(vis_Y, 0, sizeof(vis_Y));
if (Dfs(i)) break;
int tmp = INF;
for (int j = 1; j <= N; ++j) {
if( vis_Y[j] == 0 )
tmp = min(tmp, Slack[j]);
}
if(tmp == INF) return -1;
for(int j = 1; j <= N; ++j) {
if(vis_X[j]) ex_X[j] -= tmp;
if(vis_Y[j]) ex_Y[j] += tmp;
else Slack[j] -= tmp;
}
}
}
int Ans = 0;
for(int i = 1; i <= N; i++){
if(Match[i] != -1)
Ans += G[Match[i]][i];
}
return Ans;
}
int main (){
while(~scanf("%d", &N)){
int Temp;
for(int i = 1; i <= N; ++i){
for(int j = 1; j <= N; ++j){
scanf("%d", &G[i][j]);
}
}
printf("%d\n", KM());
}
return 0;
}