这道题就是一个裸的带权二分图(KM)匹配模板。
首先关于KM算法,我概念是看的这个视频(在2P)
https://www.bilibili.com/video/av60813417/?p=2&t=316
然后关于代码方面我是看的这个博客
https://blog.csdn.net/frankax/article/details/81541421
都是感觉非常不错。
然后直接写模板就可以了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int INF = 1e9+7;
const int max_ = 3e2 + 7;
int match[max_], n, map[max_][max_];
int lx[max_], ly[max_],slack[max_],visx[max_],visy[max_];
inline int read()
{
int s = 0, f = 1;
char ch = getchar();
while (ch<'0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0'&&ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * f;
}
inline int max(int x, int y) {
return x > y ? x : y;
}
inline int min(int x, int y) {
return x > y ? y : x;
}
int dfs(int now) {
visx[now] = 1;
for (register int i = 1; i <= n; i++) {
if (!visy[i] && lx[now] + ly[i] == map[now][i]) {
visy[i] = 1;
if (!match[i] || dfs(match[i])) {
match[i] = now;
return 1;
}
}
else{
slack[i] = min(slack[i], lx[now] + ly[i] - map[now][i]);
}
}
return 0;
}
void KM() {
memset(ly, 0, sizeof(ly));
memset(match, 0, sizeof(match));
for (register int i = 1; i <= n; i++) {
lx[i] = -INF;
for (register int j = 1; j <= n; j++) {
lx[i] = max(lx[i], map[i][j]);
}
}
for (register int x = 1; x <= n; x++) {
memset(slack, INF, sizeof(slack));
while (1) {
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
if (dfs(x))break;
int D = INF;
for (register int i = 1; i <= n; i++) {
if (!visy[i]) D = min(D, slack[i]);
}
for (register int i = 1; i <= n; i++) {
if (visx[i]) lx[i] -= D;
if (visy[i]) ly[i] += D;
else
{
slack[i] -= D;
}
}
}
}
}
int main() {
while (~scanf("%d", &n)) {
memset(map, 0, sizeof(map));
for (register int i = 1; i <= n; i++) {
for (register int j = 1; j <= n; j++) {
map[i][j] = read();
}
}
KM();
int ans = 0;
for (register int i = 1; i <= n; i++) {
ans += map[match[i]][i];
}
printf("%d\n", ans);
}
return 0;
}