/* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<stack> #include<cstring> #include<queue> #include<set> #include<string> #include<map> #include <time.h> #define PI acos(-1) using namespace std; typedef long long ll; typedef double db; const int maxn = 400; const ll maxm = 1e7; const int mod = 1e9+7; const int INF = 0x3f3f3f; const ll inf = 1e14 + 5; const db eps = 1e-9; const ll Max=1e19; int mapp[maxn][maxn], visx[maxn], visy[maxn]; int lx[maxn], ly[maxn]; int match[maxn]; int n; int hungry(int u) { visx[u] = true; for(int i = 0; i < n; ++i) { if(!visy[i] && lx[u] + ly[i] == mapp[u][i]) { visy[i] = true; if(match[i] == -1 || hungry(match[i])) { match[i] = u; return true; } } } return false; } void KM() { int temp; memset(lx, 0, sizeof(lx)); //初始化顶标 memset(ly, 0, sizeof(ly)); //ly[i]为0 for(int i = 0; i < n; ++i) //lx[i]为权值最大的边 for(int j = 0; j < n; ++j) lx[i] = max(lx[i], mapp[i][j]); for(int i = 0; i < n; ++i) //对n个点匹配 { while(1) { memset(visx, false, sizeof(visx)); memset(visy, false, sizeof(visy)); if(hungry(i)) //匹配成功 break; else //匹配失败,找最小值 { temp = INF; for(int j = 0; j < n; ++j) //x在交错树中 if(visx[j]) for(int k = 0; k < n; ++k) //y在交错树外 if(!visy[k] && temp > lx[j] + ly[k] - mapp[j][k]) temp = lx[j] + ly[k] - mapp[j][k]; for(int j = 0; j < n; ++j) //更新顶标 { if(visx[j]) lx[j] -= temp; if(visy[j]) ly[j] += temp; } } } } } void solve() { int ans; while(scanf("%d", &n) != EOF) { ans = 0; memset(match, -1, sizeof(match)); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) scanf("%d", &mapp[i][j]); KM(); for(int i = 0; i < n; i++) //权值相加 ans += mapp[match[i]][i]; printf("%d\n", ans); } } int main() { int t=1; //freopen("in.txt", "r", stdin); //scanf("%d", &t); while(t--) solve(); }