#include <cstdio> #include <cstring> #include <algorithm> const int MAXN = 300+10; const int INF = 0x3f3f3f3f; int n, nx, ny; int lx[MAXN], ly[MAXN]; // adjacent matrix to store graph int ma[MAXN][MAXN]; int slack[MAXN]; int match[MAXN]; bool visx[MAXN], visy[MAXN]; bool findPath(int x) { visx[x] = true; for (int y = 1; y <= ny; ++y) { if (true == visy[y]) { continue; } int tmp = lx[x] + ly[y] - ma[x][y]; if (0 == tmp) { visy[y] = true; if (-1 == match[y] || true == findPath(match[y])) { match[y] = x; return true; } } if (slack[y] > tmp) { slack[y] = tmp; } } return false; } int km() { nx = ny = n; // init... memset(match, -1, sizeof match); memset(ly, 0, sizeof ly); for (int x = 1; x <= nx; ++x) { lx[x] = -INF; for (int y = 1; y <= ny; ++y) { lx[x] = std::max(lx[x], ma[x][y]); } } for (int x = 1; x <= nx; ++x) { for (int y = 1; y <= ny; ++y) { slack[y] = INF; } while (true) { memset(visx, false, sizeof visx); memset(visy, false, sizeof visy); if (true == findPath(x)) { break; } int min_d = INF; for (int y = 1; y <= ny; ++y) { if (false == visy[y] && min_d > slack[y]) { min_d = slack[y]; } } for (int x = 1; x <= nx; ++x) { if (true == visx[x]) { lx[x] -= min_d; } } for (int y = 1; y <= ny; ++y) { if (true == visy[y]) { ly[y] += min_d; } else { slack[y] -= min_d; } } } } int res = 0; for (int y = 1; y <= ny; ++y) { if (-1 != match[y]) { res += ma[match[y]][y]; } } return res; } int main() { while (~scanf("%d", &n)) { // input graph for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { scanf("%d", &ma[i][j]); } } printf("%d ", km()); } }