#include <fstream>
#include <cstring>
#include <queue>
#include <assert.h>
using namespace std;
ifstream cin ("cc.in");
ofstream cout ("cc.out");
const int MaxN = 205, Inf = 0x3f3f3f3f;
class m_edg {
public:
int node, cap, cost;
m_edg (int _node = 0, int _cost = 0, int _cap = 1) {
node = _node;
cost = _cost;
cap = _cap;
}
};
m_edg G[10 * MaxN * MaxN];
class m_node {
public:
int nd, cost;
m_node (int _nd = 0, int _cost = 0) {
nd = _nd;
cost = _cost;
}
inline bool operator < (const m_node &other) const {
return cost > other.cost;
}
};
priority_queue <m_node> PrioQ;
int FirstNgb[MaxN], NextNgb[10 * MaxN * MaxN], father[MaxN], Dist[MaxN], used[MaxN], EdgFather[MaxN];
int n, EdgTop, Source = 0, Destination, Ans;
void AddEdge(int n1, int n2, int cost, int cap = 1) {
++EdgTop;
G[EdgTop] = m_edg(n2, cost, cap);
NextNgb[EdgTop] = FirstNgb[n1];
FirstNgb[n1] = EdgTop;
}
inline void ClearPQ() {
while (PrioQ.size()) {
PrioQ.pop();
}
}
bool Dijkstra() {
ClearPQ();
memset(father, 0, sizeof father);
memset(Dist, Inf, sizeof Dist);
memset(used, 0, sizeof used);
memset(EdgFather, 0, sizeof EdgFather);
PrioQ.push(m_node(Source, 0));
father[Source] = -1;
Dist[Source] = 0;
while (PrioQ.size()) {
m_node node = PrioQ.top();
PrioQ.pop();
if (node.cost > Dist[node.nd]) {
continue;
}
used[node.nd] = true;
for (int NxtPtr = FirstNgb[node.nd]; NxtPtr; NxtPtr = NextNgb[NxtPtr]) {
m_edg nxt = G[NxtPtr];
if (node.cost + nxt.cost < Dist[nxt.node] and nxt.cap) {
Dist[nxt.node] = node.cost + nxt.cost;
father[nxt.node] = node.nd;
EdgFather[nxt.node] = NxtPtr;
PrioQ.push(m_node(nxt.node, Dist[nxt.node]));
if (nxt.node == Destination) {
return true;
}
}
}
}
return false;
}
int RevNode(int ptr) {
return (ptr % 2 == 0) ? ptr - 1 : ptr + 1;
}
void FlowUpdate(int node = Destination) {
while (node!=0) {
assert(G[EdgFather[node]].cap+G[RevNode(EdgFather[node])].cap==1);
G[EdgFather[node]].cap = 0;
Ans+=G[EdgFather[node]].cost;
G[RevNode(EdgFather[node])].cap = 1;
node = father[node];
}
}
int main() {
cin >> n;
Destination = 2 * n + 1;
for (int i = 1; i <= n; ++i) {
for (int j = n + 1; j <= 2 * n; ++j) {
int a;
cin >> a;
AddEdge(i, j, a);
AddEdge(j, i, -a, 0);
}
AddEdge(Source, i, 0);
AddEdge(i, Source, 0, 0);
AddEdge(n + i, Destination, 0);
AddEdge(Destination, n + i, 0, 0);
}
while (Dijkstra()) {
FlowUpdate();
}
/*
for (int i = 1; i <= EdgTop; i += 2) {
if (G[i].cap == 0) {
Ans += G[i].cost;
}
}
*/
cout << Ans << '\n';
assert(Ans>=n);
return 0;
}