struct KM{
bool S[maxn], T[maxn];
int Lx[maxn], Ly[maxn];
int W[maxn][maxn];
int slack[maxn];
int myleft[maxn];
vector<int> G[maxn];
int n;
void init(int n){
this -> n = n;
for (int i = 0; i < n; i++) G[i].clear();
memset(W, 0, sizeof(W));
}
void AddEdge(int u, int v, int val){
G[u].push_back(v);
W[u][v] = val;
}
bool match(int u){
S[u] = true;
int len = G[u].size();
for (int i = 0; i < len; i++){
int v = G[u][i];
if (!T[v]){
int a = Lx[u] + Ly[v] - W[u][v];
if (!a){
T[v] = true;
if (myleft[v] == -1 || match(myleft[v])){
myleft[v] = u;
return true;
}
}
else slack[v] = min(slack[v], a);
}
}
return false;
}
void update(){
int a = inf;
for (int i = 0; i < n; i++)
if (!T[i]) a = min(a, slack[i]);
for (int i = 0; i < n; i++){
if (S[i]) Lx[i] -= a;
if (T[i]) Ly[i] += a;
else slack[i] -= a;
}
}
void solve(){
for (int i = 0; i < n; i++){
Lx[i] = *max_element(W[i], W[i]+n);
myleft[i] = -1;
Ly[i] = 0;
}
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++) slack[j] = inf;
while (true){
for (int j = 0; j < n; j++) S[j] = T[j] = 0;
if (match(i)) break; else update();
}
}
}
}