#include <bits/stdc++.h>
using namespace std;
bool _S;
int Stack[190005];
short cnt[1050005];
int a[21][21], b[21][21], S, n, i, j, ans;
struct match {
  const int INF = 1e9;
  int L[21], R[21], map[21][21], Q[21];
  int id[21], small[21], visitL[21], visitR[21];
  int Link[21], posL[21], posR[21];
  int Graph(int S) {
    for (int i = 1; i <= n; i++) posL[i] = posR[i] = L[i] = R[i] = 0;
    int maybe = 0;
    for (int i = 1; i <= n; i++)
      for (int j = 1; j <= n; j++)
        map[i][j] = ((S >> i - 1) & 1) ? a[i][j] : b[i][j],
        L[i] = max(L[i], map[i][j]);
    for (int i = 1; i <= n; i++) maybe += L[i];
    return maybe > ans;
  }
  int Find(int u, int v) {
    visitR[v] = 1;
    Link[v] = u;
    int newu = posR[v];
    if (newu) return visitL[newu] = 1, Q[++*Q] = newu, 0;
    while (v) {
      int newv = posL[Link[v]];
      posL[Link[v]] = v;
      posR[v] = Link[v];
      v = newv;
    }
    return 1;
  }
  void get(int start) {
    for (int u = 1; u <= n; u++) visitL[u] = 0;
    for (int v = 1; v <= n; v++)
      visitR[v] = id[v] = Link[v] = 0, small[v] = INF;
    visitL[Q[*Q = 1] = start] = 1;
    while (true) {
      for (int i = 1; i <= *Q; i++)
        for (int u = Q[i], v = 1; v <= n; v++)
          if (!visitR[v]) {
            int upd = L[u] + R[v] - map[u][v];
            if (!upd) {
              if (Find(u, v)) return;
            } else if (upd < small[v])
              small[v] = upd, id[v] = u;
          }
      int upd = INF;
      for (int v = 1; v <= n; v++)
        if (!visitR[v]) upd = min(upd, small[v]);
      for (int u = 1; u <= n; u++)
        if (visitL[u]) L[u] -= upd;
      for (int v = 1; v <= n; v++)
        if (visitR[v])
          R[v] += upd;
        else if (small[v] < INF)
          small[v] -= upd;
      *Q = 0;
      for (int v = 1; v <= n; v++)
        if (!visitR[v] && !small[v])
          if (Find(id[v], v)) return;
    }
  }
  void work() {
    for (int i = 1; i <= n; i++) get(i);
    int res = 0;
    for (int i = 1; i <= n; i++) res += L[i];
    for (int i = 1; i <= n; i++) res += R[i];
    ans = max(ans, res);
  }
} KM;
bool _T;
int main() {
  scanf("%d", &n);
  srand(233);
  for (i = 1; i <= n; i++)
    for (j = 1; j <= n; j++) scanf("%d", &a[i][j]);
  for (i = 1; i <= n; i++)
    for (j = 1; j <= n; j++) scanf("%d", &b[i][j]);
  for (S = 1; S < (1 << n); S++)
    if ((cnt[S] = cnt[S >> 1] + (S & 1)) == n / 2) Stack[++*Stack] = S;
  for (i = 1; i <= *Stack; i++) {
    if (KM.Graph(Stack[i])) KM.work();
    if (clock() > 1950) return printf("%d\n", ans), 0;
  }
  printf("%d\n", ans);
}
