#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxn 21
#define inf 1000000000
struct Hungary {
    int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    bool used[maxn];
    void init(int _nx, int _ny) {
        nx = _nx; ny = _ny; memset(fx, 0, sizeof(fx)); memset(fy, 0, sizeof(fy)); memset(maty, 0, sizeof(maty)); memset(which, 0, sizeof(which));
        for (int i = 0; i <= nx; i++) for (int j = 0; j <= ny; j++) cost[i][j] = inf;
    }
    void add(int x, int y, int c) {cost[x][y] = c;}
    void update(int x) {
        int y0 = 0; maty[0] = x;
        for (int y = 0; y <= ny; y++) {dist[y] = inf + 1; used[y] = false;}
        do {
            used[y0] = true;
            int x0 = maty[y0], delta = inf + 1, y1;
            for (int y = 1; y <= ny; y++) if (!used[y]) {
                int curdist = cost[x0][y] - fx[x0] - fy[y];
                if (curdist < dist[y]) {
                    dist[y] = curdist;
                    which[y] = y0;
                }
                if (dist[y] < delta) {
                    delta = dist[y];
                    y1 = y;
                }
            }
            for (int y = 0; y <= ny; y++) if (used[y]) {
                fx[maty[y]] += delta;
                fy[y] -= delta;
            }
            else dist[y] -= delta;
            y0 = y1;
        }
        while (maty[y0] != 0);
        do {
            int y1 = which[y0];
            maty[y0] = maty[y1];
            y0 = y1;
        }
        while (y0);
    }
    Hungary operator = (const Hungary& tmp) {
        nx = tmp.nx; ny = tmp.ny;
        FOR(i, 0, maxn) {
            fx[i] = tmp.fx[i];
            fy[i] = tmp.fy[i];
            maty[i] = tmp.maty[i];
        }
        return tmp;
    }
} hungary;

int n;
int a[maxn][maxn];
int b[maxn][maxn];
int ans;

void go(int pos, int bit, int cnt) {
    Hungary tmp = hungary;
    FOR(i, 0, n) if (!bit) hungary.add(pos + 1, i + 1, -a[pos][i]); else hungary.add(pos + 1, i + 1, -b[pos][i]);
    hungary.update(pos + 1);
    if (pos == n - 1) {
        if (cnt == n >> 1) {
            int tot = 0;
            for (int y = 1; y <= hungary.ny; y++) {
                int x = hungary.maty[y];
                if (hungary.cost[x][y] < inf) tot -= hungary.cost[x][y];
            }
            ans = max(ans, tot);
        }
        hungary = tmp; FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
        return;
    }
    if (cnt + n - pos - 2 >= n >> 1) go(pos + 1, 0, cnt);
    if (cnt + 1 <= n >> 1) go(pos + 1, 1, cnt + 1);
    hungary = tmp;
    FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
}

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    ans = 0;
    hungary.init(n, n); FOR(i, 0, n) hungary.add(1, i + 1, -a[0][i]);
    go(0, 0, 0);
    hungary.init(n, n); FOR(i, 0, n) hungary.add(1, i + 1, -b[0][i]);
    go(0, 1, 1);
    printf("%d", ans);
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxn 21
#define inf 1000000000
struct Hungary {
    int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    bool used[maxn];
    void init(int _nx, int _ny) {
        nx = _nx; ny = _ny; memset(fx, 0, sizeof(fx)); memset(fy, 0, sizeof(fy)); memset(maty, 0, sizeof(maty)); memset(which, 0, sizeof(which));
        for (int i = 0; i <= nx; i++) for (int j = 0; j <= ny; j++) cost[i][j] = inf;
    }
    void add(int x, int y, int c) {cost[x][y] = c;}
    void update(int x) {
        int y0 = 0; maty[0] = x;
        for (int y = 0; y <= ny; y++) {dist[y] = inf + 1; used[y] = false;}
        do {
            used[y0] = true;
            int x0 = maty[y0], delta = inf + 1, y1;
            for (int y = 1; y <= ny; y++) if (!used[y]) {
                int curdist = cost[x0][y] - fx[x0] - fy[y];
                if (curdist < dist[y]) {
                    dist[y] = curdist;
                    which[y] = y0;
                }
                if (dist[y] < delta) {
                    delta = dist[y];
                    y1 = y;
                }
            }
            for (int y = 0; y <= ny; y++) if (used[y]) {
                fx[maty[y]] += delta;
                fy[y] -= delta;
            }
            else dist[y] -= delta;
            y0 = y1;
        }
        while (maty[y0] != 0);
        do {
            int y1 = which[y0];
            maty[y0] = maty[y1];
            y0 = y1;
        }
        while (y0);
    }
    Hungary operator = (const Hungary& h) {
        nx = h.nx; ny = h.ny;
        FOR(i, 0, maxn) {
            fx[i] = h.fx[i];
            fy[i] = h.fy[i];
            maty[i] = h.maty[i];
            //which[i] = h.which[i];
            //dist[i] = h.dist[i];
        }
        return h;
    }
} hungary;

int n;
int a[maxn][maxn];
int b[maxn][maxn];
int ans;

void go(int pos, int bit, int cnt) {
    Hungary tmp = hungary;
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, -a[pos][i]); else hungary.add(pos + 1, i + 1, -b[pos][i]);
    hungary.update(pos + 1);
    if (pos == n - 1) {
        if (cnt == (n >> 1)) {
            int tot = 0;
            for (int y = 1; y <= hungary.ny; y++) {
                int x = hungary.maty[y];
                if (hungary.cost[x][y] < inf) tot -= hungary.cost[x][y];
            }
            ans = max(ans, tot);
        }
        hungary = tmp; FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
        return;
    }
    if (cnt + n - pos - 1 >= (n >> 1)) go(pos + 1, 0, cnt);
    if (cnt + 1 <= (n >> 1)) go(pos + 1, 1, cnt + 1);
    hungary = tmp;
    FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
}

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    ans = 0;
    hungary.init(n, n); FOR(i, 0, n) hungary.add(1, i + 1, -a[0][i]);
    go(0, 0, 0);
    hungary.init(n, n); FOR(i, 0, n) hungary.add( 1, i + 1, -b[0][i]);
    go(0, 1, 1);
    printf("%d", ans);
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxn 21
#define inf 1000000000
struct Hungary {
    int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    bool used[maxn];
    void init(int _nx, int _ny) {
        nx = _nx; ny = _ny; memset(fx, 0, sizeof(fx)); memset(fy, 0, sizeof(fy)); memset(maty, 0, sizeof(maty)); memset(which, 0, sizeof(which));
        for (int i = 0; i <= nx; i++) for (int j = 0; j <= ny; j++) cost[i][j] = inf;
    }
    void add(int x, int y, int c) {cost[x][y] = c;}
    void update(int x) {
        int y0 = 0; maty[0] = x;
        for (int y = 0; y <= ny; y++) {dist[y] = inf + 1; used[y] = false;}
        do {
            used[y0] = true;
            int x0 = maty[y0], delta = inf + 1, y1;
            for (int y = 1; y <= ny; y++) if (!used[y]) {
                int curdist = cost[x0][y] - fx[x0] - fy[y];
                if (curdist < dist[y]) {
                    dist[y] = curdist;
                    which[y] = y0;
                }
                if (dist[y] < delta) {
                    delta = dist[y];
                    y1 = y;
                }
            }
            for (int y = 0; y <= ny; y++) if (used[y]) {
                fx[maty[y]] += delta;
                fy[y] -= delta;
            }
            else dist[y] -= delta;
            y0 = y1;
        }
        while (maty[y0] != 0);
        do {
            int y1 = which[y0];
            maty[y0] = maty[y1];
            y0 = y1;
        }
        while (y0);
    }
    Hungary operator = (const Hungary& h) {
        nx = h.nx; ny = h.ny;
        FOR(i, 0, maxn) {
            //fx[i] = h.fx[i];
            //fy[i] = h.fy[i];
            maty[i] = h.maty[i];
            which[i] = h.which[i];
            dist[i] = h.dist[i];
        }
        return h;
    }
} hungary;

int n;
int a[maxn][maxn];
int b[maxn][maxn];
int ans;

void go(int pos, int bit, int cnt) {
    Hungary tmp = hungary;
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, -a[pos][i]); else hungary.add(pos + 1, i + 1, -b[pos][i]);
    hungary.update(pos + 1);
    if (pos == n - 1) {
        if (cnt == (n >> 1)) {
            int tot = 0;
            for (int y = 1; y <= hungary.ny; y++) {
                int x = hungary.maty[y];
                if (hungary.cost[x][y] < inf) tot -= hungary.cost[x][y];
            }
            ans = max(ans, tot);
        }
        hungary = tmp; FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
        return;
    }
    if (cnt + n - pos - 1 >= (n >> 1)) go(pos + 1, 0, cnt);
    if (cnt + 1 <= (n >> 1)) go(pos + 1, 1, cnt + 1);
    hungary = tmp;
    FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
}

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    ans = 0;
    hungary.init(n, n); FOR(i, 0, n) hungary.add(1, i + 1, -a[0][i]);
    go(0, 0, 0);
    hungary.init(n, n); FOR(i, 0, n) hungary.add( 1, i + 1, -b[0][i]);
    go(0, 1, 1);
    printf("%d", ans);
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxn 21
#define inf 1000000000
struct Hungary {
    int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    bool used[maxn];
    void init(int _nx, int _ny) {
        nx = _nx; ny = _ny; memset(fx, 0, sizeof(fx)); memset(fy, 0, sizeof(fy)); memset(maty, 0, sizeof(maty)); memset(which, 0, sizeof(which));
        for (int i = 0; i <= nx; i++) for (int j = 0; j <= ny; j++) cost[i][j] = inf;
    }
    void add(int x, int y, int c) {cost[x][y] = c;}
    void update(int x) {
        //for (int x = 1; x <= nx; x++) {
        int y0 = 0; maty[0] = x;
        for (int y = 0; y <= ny; y++) {dist[y] = inf + 1; used[y] = false;}
        do {
            used[y0] = true;
            int x0 = maty[y0], delta = inf + 1, y1;
            for (int y = 1; y <= ny; y++) if (!used[y]) {
                int curdist = cost[x0][y] - fx[x0] - fy[y];
                if (curdist < dist[y]) {
                    dist[y] = curdist;
                    which[y] = y0;
                }
                if (dist[y] < delta) {
                    delta = dist[y];
                    y1 = y;
                }
            }
            for (int y = 0; y <= ny; y++) if (used[y]) {
                fx[maty[y]] += delta;
                fy[y] -= delta;
            }
            else dist[y] -= delta;
            y0 = y1;
        }
        while (maty[y0] != 0);
        do {
            int y1 = which[y0];
            maty[y0] = maty[y1];
            y0 = y1;
        }
        while (y0);
        //}
        //int ret = 0;
        //for (int y = 1; y <= ny; y++) {
        //int x = maty[y];
        //if (cost[x][y] < inf) ret += cost[x][y];
        //}
        //return ret;
    }
} hungary;

int n;
int a[maxn][maxn];
int b[maxn][maxn];
int ans = 0;

void go(int pos, int bit, int cnt) {

    Hungary tmp; //int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    tmp.nx = hungary.nx;
    tmp.ny = hungary.ny;
    FOR(i, 0, maxn) {
        tmp.fx[i] = hungary.fx[i];
        tmp.fy[i] = hungary.fy[i];
        tmp.maty[i] = hungary.maty[i];
        tmp.which[i] = hungary.which[i];
        tmp.dist[i] = hungary.dist[i];
        //FOR(j, 0, maxn) tmp.cost[i][j] = hungary.cost[i][j];
    }
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, -a[pos][i]); else hungary.add(pos + 1, i + 1, -b[pos][i]);
    hungary.update(pos + 1);

    if (pos == n - 1) {
        if (cnt == (n >> 1)) {
            int tot = 0;
            for (int y = 1; y <= hungary.ny; y++) {
                int x = hungary.maty[y];
                if (hungary.cost[x][y] < inf) tot -= hungary.cost[x][y];
            }
            ans = max(ans, tot);
        }
        hungary.nx = tmp.nx;
    hungary.ny = tmp.ny;
    FOR(i, 0, maxn) {
        hungary.fx[i] = tmp.fx[i];
        hungary.fy[i] = tmp.fy[i];
        hungary.maty[i] = tmp.maty[i];
        hungary.which[i] = tmp.which[i];
        hungary.dist[i] = tmp.dist[i];
        //FOR(j, 0, maxn) hungary.cost[i][j] = tmp.cost[i][j];
    }
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, inf); else hungary.add(pos + 1, i + 1, inf);
        return;
    }

    if (cnt + n - pos - 1 >= (n >> 1)) go(pos + 1, 0, cnt);
    if (cnt + 1 <= (n >> 1)) go(pos + 1, 1, cnt + 1);
    hungary.nx = tmp.nx;
    hungary.ny = tmp.ny;
    FOR(i, 0, maxn) {
        hungary.fx[i] = tmp.fx[i];
        hungary.fy[i] = tmp.fy[i];
        hungary.maty[i] = tmp.maty[i];
        hungary.which[i] = tmp.which[i];
        hungary.dist[i] = tmp.dist[i];
        //FOR(j, 0, maxn) hungary.cost[i][j] = tmp.cost[i][j];
    }
    FOR(i, 0, n) hungary.add(pos + 1, i + 1, inf);
}

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    hungary.init(n, n);
    Hungary tmp; //int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    tmp.nx = hungary.nx;
    tmp.ny = hungary.ny;
    FOR(i, 0, maxn) {
        tmp.fx[i] = hungary.fx[i];
        tmp.fy[i] = hungary.fy[i];
        tmp.maty[i] = hungary.maty[i];
        tmp.which[i] = hungary.which[i];
        tmp.dist[i] = hungary.dist[i];
        //FOR(j, 0, maxn) tmp.cost[i][j] = hungary.cost[i][j];
    }
    FOR(i, 0, n) hungary.add(1, i + 1, -a[0][i]);
    go(0, 0, 0);
     FOR(i, 0, maxn) {
        hungary.fx[i] = tmp.fx[i];
        hungary.fy[i] = tmp.fy[i];
        hungary.maty[i] = tmp.maty[i];
        hungary.which[i] = tmp.which[i];
        hungary.dist[i] = tmp.dist[i];
        //FOR(j, 0, maxn) hungary.cost[i][j] = tmp.cost[i][j];
    }
    FOR(i, 0, n) hungary.add( 1, i + 1, inf);
    go(0, 1, 1);
    cout<<ans;
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxn 21
#define inf 1000000000
struct Hungary {
    int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    bool used[maxn];
    void init(int _nx, int _ny) {
        nx = _nx; ny = _ny; memset(fx, 0, sizeof(fx)); memset(fy, 0, sizeof(fy)); memset(maty, 0, sizeof(maty)); memset(which, 0, sizeof(which));
        for (int i = 0; i <= nx; i++) for (int j = 0; j <= ny; j++) cost[i][j] = inf;
    }
    void add(int x, int y, int c) {cost[x][y] = c;}
    void update(int x) {
        //for (int x = 1; x <= nx; x++) {
        int y0 = 0; maty[0] = x;
        for (int y = 0; y <= ny; y++) {dist[y] = inf + 1; used[y] = false;}
        do {
            used[y0] = true;
            int x0 = maty[y0], delta = inf + 1, y1;
            for (int y = 1; y <= ny; y++) if (!used[y]) {
                int curdist = cost[x0][y] - fx[x0] - fy[y];
                if (curdist < dist[y]) {
                    dist[y] = curdist;
                    which[y] = y0;
                }
                if (dist[y] < delta) {
                    delta = dist[y];
                    y1 = y;
                }
            }
            for (int y = 0; y <= ny; y++) if (used[y]) {
                fx[maty[y]] += delta;
                fy[y] -= delta;
            }
            else dist[y] -= delta;
            y0 = y1;
        }
        while (maty[y0] != 0);
        do {
            int y1 = which[y0];
            maty[y0] = maty[y1];
            y0 = y1;
        }
        while (y0);
        //}
        //int ret = 0;
        //for (int y = 1; y <= ny; y++) {
        //int x = maty[y];
        //if (cost[x][y] < inf) ret += cost[x][y];
        //}
        //return ret;
    }
} hungary;

int n;
int a[maxn][maxn];
int b[maxn][maxn];
int ans = 0;

void go(int pos, int bit, int cnt) {

    Hungary tmp; //int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    tmp.nx = hungary.nx;
    tmp.ny = hungary.ny;
    FOR(i, 0, maxn) {
        tmp.fx[i] = hungary.fx[i];
        tmp.fy[i] = hungary.fy[i];
        tmp.maty[i] = hungary.maty[i];
        tmp.which[i] = hungary.which[i];
        tmp.dist[i] = hungary.dist[i];
        //FOR(j, 0, maxn) tmp.cost[i][j] = hungary.cost[i][j];
    }
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, -a[pos][i]); else hungary.add(pos + 1, i + 1, -b[pos][i]);
    hungary.update(pos + 1);

    if (pos == n - 1) {
        if (cnt == (n >> 1)) {
            int tot = 0;
            for (int y = 1; y <= hungary.ny; y++) {
                int x = hungary.maty[y];
                if (hungary.cost[x][y] < inf) tot -= hungary.cost[x][y];
            }
            ans = max(ans, tot);
        }
        hungary.nx = tmp.nx;
    hungary.ny = tmp.ny;
    FOR(i, 0, maxn) {
        hungary.fx[i] = tmp.fx[i];
        hungary.fy[i] = tmp.fy[i];
        hungary.maty[i] = tmp.maty[i];
        hungary.which[i] = tmp.which[i];
        hungary.dist[i] = tmp.dist[i];
        //FOR(j, 0, maxn) hungary.cost[i][j] = tmp.cost[i][j];
    }
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, inf); else hungary.add(pos + 1, i + 1, inf);
        return;
    }

    if (cnt + n - pos - 1 >= (n >> 1)) go(pos + 1, 0, cnt);
    if (cnt + 1 <= (n >> 1)) go(pos + 1, 1, cnt + 1);
    hungary.nx = tmp.nx;
    hungary.ny = tmp.ny;
    FOR(i, 0, maxn) {
        hungary.fx[i] = tmp.fx[i];
        hungary.fy[i] = tmp.fy[i];
        hungary.maty[i] = tmp.maty[i];
        hungary.which[i] = tmp.which[i];
        hungary.dist[i] = tmp.dist[i];
        //FOR(j, 0, maxn) hungary.cost[i][j] = tmp.cost[i][j];
    }
    FOR(i, 0, n) if (bit == 1) hungary.add(pos + 1, i + 1, inf); else hungary.add(pos + 1, i + 1, inf);
}

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    hungary.init(n, n);
    Hungary tmp; //int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    tmp.nx = hungary.nx;
    tmp.ny = hungary.ny;
    FOR(i, 0, maxn) {
        tmp.fx[i] = hungary.fx[i];
        tmp.fy[i] = hungary.fy[i];
        tmp.maty[i] = hungary.maty[i];
        tmp.which[i] = hungary.which[i];
        tmp.dist[i] = hungary.dist[i];
        //FOR(j, 0, maxn) tmp.cost[i][j] = hungary.cost[i][j];
    }
    FOR(i, 0, n) hungary.add(1, i + 1, -a[0][i]);
    go(0, 0, 0);
     FOR(i, 0, maxn) {
        hungary.fx[i] = tmp.fx[i];
        hungary.fy[i] = tmp.fy[i];
        hungary.maty[i] = tmp.maty[i];
        hungary.which[i] = tmp.which[i];
        hungary.dist[i] = tmp.dist[i];
        //FOR(j, 0, maxn) hungary.cost[i][j] = tmp.cost[i][j];
    }
    FOR(i, 0, n) hungary.add( 1, i + 1, -b[0][i]);
    go(0, 1, 1);
    cout<<ans;
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxn 21
#define inf 1000000000
struct Hungary {
    int nx, ny, cost[maxn][maxn], fx[maxn], fy[maxn], maty[maxn], which[maxn], dist[maxn];
    bool used[maxn];
    void init(int _nx, int _ny) {
        nx = _nx; ny = _ny; memset(fx, 0, sizeof(fx)); memset(fy, 0, sizeof(fy)); memset(maty, 0, sizeof(maty)); memset(which, 0, sizeof(which)); memset(dist, 0, sizeof(dist));
        for (int i = 0; i <= nx; i++) for (int j = 0; j <= ny; j++) cost[i][j] = inf;
    }
    void add(int x, int y, int c) {cost[x][y] = c;}
    int mincost() {
        for (int x = 1; x <= nx; x++) {
            int y0 = 0; maty[0] = x;
            for (int y = 0; y <= ny; y++) {dist[y] = inf + 1; used[y] = false;}
            do {
                used[y0] = true;
                int x0 = maty[y0], delta = inf + 1, y1;
                for (int y = 1; y <= ny; y++) if (!used[y]) {
                    int curdist = cost[x0][y] - fx[x0] - fy[y];
                    if (curdist < dist[y]) {
                        dist[y] = curdist;
                        which[y] = y0;
                    }
                    if (dist[y] < delta) {
                        delta = dist[y];
                        y1 = y;
                    }
                }
                for (int y = 0; y <= ny; y++) if (used[y]) {
                    fx[maty[y]] += delta;
                    fy[y] -= delta;
                } else dist[y] -= delta;
                y0 = y1;
            }
            while (maty[y0] != 0);
            do {
                int y1 = which[y0];
                maty[y0] = maty[y1];
                y0 = y1;
            }
            while (y0);
        }
        int ret = 0;
        for (int y = 1; y <= ny; y++) {
            int x = maty[y];
            if (cost[x][y] < inf) ret += cost[x][y];
        }
        return ret;
    }
} hungary;

int n;
int a[maxn][maxn];
int b[maxn][maxn];

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    int ans = 0;
    FOR(i, 0, 1 << n) {
        if (clock() > 1990) break;
        bool flag[maxn]; ms(flag, 0); int cnt = 0;
        FOR(j, 0, n) if (i & 1 << j) {flag[j] = 1; cnt++;}
        if (cnt != n >> 1) continue;
        hungary.init(n, n);
        FOR(j, 0, n) FOR(k, 0, n) {
            if (flag[k]) hungary.add(j + 1, k + 1, -a[j][k]);
            else hungary.add(j + 1, k + 1, -b[j][k]);
        }
        ans = min(ans, hungary.mincost());
    }
    printf("%d", -ans);
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define ms(s, n) memset(s, n, sizeof(s))
#define FOR(i, a, b) for(int i = (a); i < (b); i++)
#define FORd(i, a, b) for(int i = (a) - 1; i >= (b); i--)
#define sz(a) int((a).size())
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vii;
ll gcd(ll a, ll b) {ll r; while (b != 0) {r = a % b; a = b; b = r;} return a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

#define maxv 110
#define maxe 11000
#define linf 1000000000000000000LL
struct MincostFlow {
    int n, s, t, E, adj[maxe], next[maxe], last[maxv], which[maxv];
    long long totalCost, totalFlow, cap[maxe], flow[maxe], cost[maxe], pot[maxe], dist[maxv];
    void init(int _n, int _s, int _t) {
        n = _n; s = _s; t = _t;
        memset(last, -1, sizeof(last)); E = 0;
    }
    void add(int u, int v, long long ca, long long co) {
        adj[E] = v; cap[E] = ca; flow[E] = 0; cost[E] = +co; next[E] = last[u]; last[u] = E++;
        adj[E] = u; cap[E] =  0; flow[E] = 0; cost[E] = -co; next[E] = last[v]; last[v] = E++;
    }
    void bellman() {
        bool stop = false;
        memset(pot, 0, sizeof(pot));
        while (!stop) {
            stop = true;
            for (int u = 0; u < n; u++) for (int e = last[u]; e != -1; e = next[e]) if (flow[e] < cap[e]) {
                int v = adj[e];
                if (pot[v] > pot[u] + cost[e]) {
                    pot[v] = pot[u] + cost[e];
                    stop = false;
                }
            }
        }
    }
    bool dijkstra() {
        typedef pair<long long, int> node;
        priority_queue<node, vector<node>, greater<node> > que;
        for (int u = 0; u < n; u++) dist[u] = linf;
        dist[s] = 0;
        que.push(make_pair(0, s));
        while (!que.empty()) {
            long long dnow = que.top().first;
            int u = que.top().second;
            que.pop();
            if (dnow > dist[u]) continue;
            for (int e = last[u]; e != -1; e = next[e]) if (flow[e] < cap[e]) {
                int v = adj[e];
                long long dnext = dnow + cost[e] + pot[u] - pot[v];
                if (dist[v] > dnext) {
                    dist[v] = dnext;
                    which[v] = e;
                    que.push(make_pair(dnext, v));
                }
            }
        }
        return dist[t] < linf;
    }
    bool maxflow(long long desireFlow = linf) {
        totalCost = totalFlow = 0;
        bellman();
        while (totalFlow < desireFlow) {
            if (!dijkstra()) return false;
            long long delta = desireFlow - totalFlow;
            for (int v = t, e = which[v]; v != s; v = adj[e ^ 1], e = which[v]) delta = min(delta, cap[e] - flow[e]);
            for (int v = t, e = which[v]; v != s; v = adj[e ^ 1], e = which[v]) {
                flow[e] += delta;
                flow[e ^ 1] -= delta;
            }
            totalFlow += delta;
            totalCost += delta * (dist[t] - pot[s] + pot[t]);
            for (int u = 0; u < n; u++) pot[u] += dist[u];
        }
        return true;
    }
} mcf;

const int maxn = 21;
int n;
int a[maxn][maxn];
int b[maxn][maxn];

void solve() {
    scanf("%d", &n);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &a[i][j]);
    FOR(i, 0, n) FOR(j, 0, n) scanf("%d", &b[i][j]);
    mcf.init(4 * n + 4, 4 * n + 3, 4 * n + 2);
    FOR(i, 0, n) mcf.add(4 * n + 3, i, 1, 0);
    FOR(i, 0, n) FOR(j, 0, n) mcf.add(i, j + n, 1, 0);
    FOR(i, 0, n) FOR(j, 0, n){
        mcf.add(i + n, j + 2 * n, 1, -a[i][j]);
        mcf.add(i + n, j + 3 * n, 1, -b[i][j]);
    }
    FOR(i, 0, n) {
        mcf.add(i + 2 * n, 4 * n, 1, 0);
        mcf.add(i + 3 * n, 4 * n + 1, 1, 0);
    }
    mcf.add(4 * n, 4 * n + 2, n >> 1, 0);
    mcf.add(4 * n + 1, 4 * n + 2, n >> 1, 0);
    mcf.maxflow();
    cout<<-mcf.totalCost;
}

int main() {
    //ios_base::sync_with_stdio(0); cin.tie(NULL);
#ifdef _LOCAL_
    freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#endif
    solve();
#ifdef _LOCAL_
    printf("\nTime elapsed: %dms", 1000 * clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <ctime>
#include <cstdlib>
using namespace std;

int A[21][21], B[21][21];
int n;
int my[21], vx[21], vy[21];
int ans = 0;
int bx[21], by[21], slack[21];
int f[21][21];

int find(int x) {
    bx[x] = 1;
    for (int i = 1; i <= n; ++i)
        if (vx[x] + vy[i] == f[x][i]) {
            if (!by[i]) {
                by[i] = 1;
                if (my[i] == 0 || find(my[i])) {
                    my[i] = x;
                    return 1;
                }
            }
        }
        else slack[i] = min(slack[i], (vx[x] + vy[i]) - f[x][i]);
    return 0;
}

void solve(int x) {
    //return ;
    memset(slack, 63, sizeof(slack));
    while (1) {
        memset(bx, 0, sizeof(bx));
        memset(by, 0, sizeof(by));
        if (find(x)) return ;
        int d = 1 << 30;
        for (int i = 1; i <= n; ++i)
            if (!by[i])
                d = min(d, slack[i]);
        for (int i = 1; i <= x; ++i)
            if (bx[i]) {
                vx[i] -= d;
            }
        for (int i = 1; i <= n; ++i)
            if (by[i]) {
                vy[i] += d;
            }
            else slack[i] -= d;
    }
}

void dfs(int x, int n1, int n2) {
    if (x > n) {
        int ans1 = 0;
        for (int i = 1; i <= n; ++i)
            ans1 += f[my[i]][i];
        ans = max(ans, ans1);
        return ;
    }
    if (n1 + n1 < n) {
        int MY[21], VX[21], VY[21];
        memcpy(MY, my, sizeof(my));
        memcpy(VX, vx, sizeof(vx));
        memcpy(VY, vy, sizeof(vy));
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = A[x][i];
            vx[x] = max(vx[x], A[x][i]);
        }
        solve(x);
        dfs(x + 1, n1 + 1, n2);
        memcpy(my, MY, sizeof(my));
        memcpy(vx, VX, sizeof(vx));
        memcpy(vy, VY, sizeof(vy));
    }
    if (n2 + n2 < n) {
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = B[x][i];
            vx[x] = max(vx[x], B[x][i]);
        }
        solve(x);
        dfs(x + 1, n1, n2 + 1);
    }
}

int main() {
    srand(time(NULL));
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &A[i][j]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &B[i][j]);
    for (int i = 2; i <= n; ++i) {
        int k = rand() % (i - 1) + 1;
        for (int j = 1; j <= n; ++j) {
            swap(A[i][j], A[k][j]);
            swap(B[i][j], B[k][j]);
        }
    }
    dfs(1, 0, 0);
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int A[25][25], B[25][25];
int n;
vector<vector<int> > f;
vector<int> my, vx, vy;
int ans = 0;
int bx[25], by[25], slack[25];

int find(int x) {
    bx[x] = 1;
    for (int i = 1; i <= n; ++i)
        if (vx[x] + vy[i] == f[x][i]) {
            if (!by[i]) {
                by[i] = 1;
                if (my[i] == 0 || find(my[i])) {
                    my[i] = x;
                    return 1;
                }
            }
        }
        else slack[i] = min(slack[i], (vx[x] + vy[i]) - f[x][i]);
    return 0;
}

void solve(int x) {
    memset(slack, 63, sizeof(slack));
    while (1) {
        memset(bx, 0, sizeof(bx));
        memset(by, 0, sizeof(by));
        if (find(x)) return ;
        int d = 1 << 30;
        for (int i = 1; i <= n; ++i)
            if (!by[i])
                d = min(d, slack[i]);
        for (int i = 1; i <= x; ++i)
            if (bx[i]) {
                vx[i] -= d;
            }
        for (int i = 1; i <= n; ++i)
            if (by[i]) {
                vy[i] += d;
            }
            else slack[i] -= d;
    }
}

void dfs(int x, int n1, int n2) {
    if (x > n) {
        int ans1 = 0;
        for (int i = 1; i <= n; ++i)
            ans1 += f[my[i]][i];
        ans = max(ans, ans1);
        return ;
    }
    if (n1 + n1 < n) {
        vector<vector<int> > F = f;
        vector<int> MY = my;
        vector<int> VX = vx, VY = vy;
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = A[x][i];
            vx[x] = max(vx[x], A[x][i]);
        }
        solve(x);
        dfs(x + 1, n1 + 1, n2);
        my = MY;  f = F;
        vx = VX;  vy = VY;
    }
    if (n2 + n2 < n) {
        vector<vector<int> > F = f;
        vector<int> MY = my;
        vector<int> VX = vx, VY = vy;
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = B[x][i];
            vx[x] = max(vx[x], B[x][i]);
        }
        solve(x);
        dfs(x + 1, n1, n2 + 1);
        my = MY;  f = F;
        vx = VX;  vy = VY;
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &A[i][j]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &B[i][j]);
    f.resize(n + 1);
    my.resize(n + 1);
    vx.resize(n + 1);
    vy.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
        vy[i] = 0;
        my[i] = 0;
    }
    for (int i = 1; i <= n; ++i)
        f[i].resize(n + 1);
    dfs(1, 0, 0);
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int A[25][25], B[25][25];
int n;
vector<int> my, vx, vy;
int ans = 0;
int bx[25], by[25], slack[25];
int f[25][25];

int find(int x) {
    bx[x] = 1;
    for (int i = 1; i <= n; ++i)
        if (vx[x] + vy[i] == f[x][i]) {
            if (!by[i]) {
                by[i] = 1;
                if (my[i] == 0 || find(my[i])) {
                    my[i] = x;
                    return 1;
                }
            }
        }
        else slack[i] = min(slack[i], (vx[x] + vy[i]) - f[x][i]);
    return 0;
}

void solve(int x) {
    //return ;
    memset(slack, 63, sizeof(slack));
    while (1) {
        memset(bx, 0, sizeof(bx));
        memset(by, 0, sizeof(by));
        if (find(x)) return ;
        int d = 1 << 30;
        for (int i = 1; i <= n; ++i)
            if (!by[i])
                d = min(d, slack[i]);
        for (int i = 1; i <= x; ++i)
            if (bx[i]) {
                vx[i] -= d;
            }
        for (int i = 1; i <= n; ++i)
            if (by[i]) {
                vy[i] += d;
            }
            else slack[i] -= d;
    }
}

void dfs(int x, int n1, int n2) {
    if (x > n) {
        int ans1 = 0;
        for (int i = 1; i <= n; ++i)
            ans1 += f[my[i]][i];
        ans = max(ans, ans1);
        return ;
    }
    if (n1 + n1 < n) {
        vector<int> MY = my;
        vector<int> VX = vx, VY = vy;
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = A[x][i];
            vx[x] = max(vx[x], A[x][i]);
        }
        solve(x);
        dfs(x + 1, n1 + 1, n2);
        my = MY;
        vx = VX;  vy = VY;
    }
    if (n2 + n2 < n) {
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = B[x][i];
            vx[x] = max(vx[x], B[x][i]);
        }
        solve(x);
        dfs(x + 1, n1, n2 + 1);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &A[i][j]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
        scanf("%d", &B[i][j]);
    my.resize(n + 1);
    vx.resize(n + 1);
    vy.resize(n + 1);
    for (int i = 1; i <= n; ++i) {
        vy[i] = 0;
        my[i] = 0;
    }
    dfs(1, 0, 0);
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int A[21][21], B[21][21];
int n;
int my[21], vx[21], vy[21];
int ans = 0;
int bx[21], by[21], slack[21];
int f[21][21];

int find(int x) {
    bx[x] = 1;
    for (int i = 1; i <= n; ++i)
        if (vx[x] + vy[i] == f[x][i]) {
            if (!by[i]) {
                by[i] = 1;
                if (my[i] == 0 || find(my[i])) {
                    my[i] = x;
                    return 1;
                }
            }
        }
        else slack[i] = min(slack[i], (vx[x] + vy[i]) - f[x][i]);
    return 0;
}

void solve(int x) {
    //return ;
    memset(slack, 63, sizeof(slack));
    while (1) {
        memset(bx, 0, sizeof(bx));
        memset(by, 0, sizeof(by));
        if (find(x)) return ;
        int d = 1 << 30;
        for (int i = 1; i <= n; ++i)
            if (!by[i])
                d = min(d, slack[i]);
        for (int i = 1; i <= x; ++i)
            if (bx[i]) {
                vx[i] -= d;
            }
        for (int i = 1; i <= n; ++i)
            if (by[i]) {
                vy[i] += d;
            }
            else slack[i] -= d;
    }
}

void dfs(int x, int n1, int n2) {
    if (x > n) {
        int ans1 = 0;
        for (int i = 1; i <= n; ++i)
            ans1 += f[my[i]][i];
        ans = max(ans, ans1);
        return ;
    }
    if (n1 + n1 < n) {
        int MY[21], VX[21], VY[21];
        memcpy(MY, my, sizeof(my));
        memcpy(VX, vx, sizeof(vx));
        memcpy(VY, vy, sizeof(vy));
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = A[x][i];
            vx[x] = max(vx[x], A[x][i]);
        }
        solve(x);
        dfs(x + 1, n1 + 1, n2);
        memcpy(my, MY, sizeof(my));
        memcpy(vx, VX, sizeof(vx));
        memcpy(vy, VY, sizeof(vy));
    }
    if (n2 + n2 < n) {
        vx[x] = -1;
        for (int i = 1; i <= n; ++i) {
            f[x][i] = B[x][i];
            vx[x] = max(vx[x], B[x][i]);
        }
        solve(x);
        dfs(x + 1, n1, n2 + 1);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &A[i][j]);
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            scanf("%d", &B[i][j]);
    dfs(1, 0, 0);
    cout << ans << endl;
    return 0;
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<memory.h>
#include<map>
#include<set>
#include<queue>
#include<list>
#include<sstream>
#include<cstring>
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define SS stringstream
#define sqr(x) ((x)*(x))
#define m0(x) memset(x,0,sizeof(x))
#define m1(x) memset(x,63,sizeof(x))
#define CC(x) cout << (x) << endl
#define pw(x) (1ll<<(x))
#define buli(x) __builtin_popcountll(x)
#define forn(i, n) for(int i = 0 ; (i) < (n) ; ++i)
#define M 1000000007
#define N 211111

#define TASK "1"

using namespace std;
typedef pair<int,int> pt;

int n;
int a[2][22][22];

int S, T;
int yy[88], cs[88], xx[88], pp[88], fl[88];
int f[88], d[88], ww[88], pr[88];
int kk;

void ae(int x, int y, int ff, int coco) {
	yy[++kk] = y;
	cs[kk] = coco;
	fl[kk] = ff;
	pp[kk] = xx[x];
 	xx[x] = kk;

	yy[++kk] = x;
	cs[kk] = -coco;
	fl[kk] = 0;
	pp[kk] = xx[y];
 	xx[y] = kk;

}

priority_queue<pair<int, int> > Q;

int main(){
//	freopen(TASK".in","r",stdin);
//	freopen(TASK".out","w",stdout);
	cin >> n;
	for (int dd = 0; dd < 2; dd++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
		cin >> a[dd][i][j];
		a[dd][i][j] = 1e6 - a[dd][i][j];
	}

	int ans = 0;
	for (int o = 0; o < pw(n); o++) {
		if (__builtin_popcount(o) != n / 2) continue;

		S = n + n;
		T = S + 1;
		for (int i = 0; i <= T; i++) xx[i] = 0;
		kk = 1;

		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
			int dd = 0;
			if (o & pw(j)) dd = 1;

			ae(i, j + n, 1, a[dd][i][j]);
		}
		for (int i = 0; i < n; i++) ae(S, i, 1, 0);
		for (int i = 0; i < n; i++) ae(i + n, T, 1, 0);

		for (int i = 0; i <= T; i++) {
			ww[i] = 0;
		}

		int cur = 0;
		for (int it = 0; it < n; it++) {
			for (int i = 0; i <= T; i++) {
				f[i] = 0;
				d[i] = 1e9;
			}
			d[S] = 0;
			while(Q.size() > 0) Q.pop();
			Q.push(mp(0, S));
			for (;;) {
				while (Q.size() > 0 && f[Q.top().S]) Q.pop();
				if (Q.size() == 0) break;
				int x = Q.top().S;
				f[x] = 1;
				for (int w = xx[x]; w; w = pp[w]) if (fl[w] > 0) {
					int to = yy[w];
					int dist = d[x] + cs[w] + ww[x] - ww[to];
					if (dist < d[to]) {
						d[to] = dist;
						pr[to] = w;
						Q.push(mp(-dist, to));
					}
				}
			}
			int x = T;
			while (x != S) {
				cur += cs[pr[x]];
				fl[pr[x]]--;
				fl[pr[x] ^ 1]++;
				x = yy[pr[x] ^ 1];
			}
			for (int i = 0; i <= T; i++) if (d[i] != 1e9) ww[i] += d[i];
		}
		ans = max(ans, 1000000 * n - cur);
	}
	cout << ans << endl;
	return 0;
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<memory.h>
#include<map>
#include<set>
#include<queue>
#include<list>
#include<sstream>
#include<cstring>
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define SS stringstream
#define sqr(x) ((x)*(x))
#define m0(x) memset(x,0,sizeof(x))
#define m1(x) memset(x,63,sizeof(x))
#define CC(x) cout << (x) << endl
#define pw(x) (1ll<<(x))
#define buli(x) __builtin_popcountll(x)
#define forn(i, n) for(int i = 0 ; (i) < (n) ; ++i)
#define M 1000000007
#define N 211111

#define TASK "1"

using namespace std;
typedef pair<int,int> pt;

int n;
int a[2][22][22];

int S, T;
int yy[8888], cs[8888], xx[8888], pp[8888], fl[8888];
int f[8888], d[8888], ww[8888], pr[8888];
int kk;

void ae(int x, int y, int ff, int coco) {
	yy[++kk] = y;
	cs[kk] = coco;
	fl[kk] = ff;
	pp[kk] = xx[x];
 	xx[x] = kk;

	yy[++kk] = x;
	cs[kk] = -coco;
	fl[kk] = 0;
	pp[kk] = xx[y];
 	xx[y] = kk;

}

int p[22];

int val(int o) {

		S = n + n;
		T = S + 1;
		for (int i = 0; i <= T; i++) xx[i] = 0;
		kk = 1;

		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
			int dd = 0;
			if (o & pw(j)) dd = 1;

			ae(i, j + n, 1, a[dd][i][j]);
		}
		for (int i = 0; i < n; i++) ae(S, i, 1, 0);
		for (int i = 0; i < n; i++) ae(i + n, T, 1, 0);

		for (int i = 0; i <= T; i++) {
			ww[i] = 0;
		}

		int cur = 0;
		for (int it = 0; it < n; it++) {
			for (int i = 0; i <= T; i++) {
				f[i] = 0;
				d[i] = 1e9;
			}
			d[S] = 0;
			for (;;) {
				int mi = 1e9;
				int x = -1;
				for (int i = 0; i <= T; i++) if (!f[i] && d[i] < mi) {
					mi = d[i];
					x = i;
				}
				if (x == -1) break;
				f[x] = 1;
				for (int w = xx[x]; w; w = pp[w]) if (fl[w] > 0) {
					int to = yy[w];
					int dist = d[x] + cs[w] + ww[x] - ww[to];
					if (dist < d[to]) {
						d[to] = dist;
						pr[to] = w;
					}
				}
			}
			int x = T;
			while (x != S) {
				cur += cs[pr[x]];
				fl[pr[x]]--;
				fl[pr[x] ^ 1]++;
				x = yy[pr[x] ^ 1];
			}
			for (int i = 0; i <= T; i++) if (d[i] != 1e9) ww[i] += d[i];
		}
		return 1e6 * n - cur;
}

int main(){
//	freopen(TASK".in","r",stdin);
//	freopen(TASK".out","w",stdout);
	cin >> n;
	for (int dd = 0; dd < 2; dd++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
		cin >> a[dd][i][j];
		a[dd][i][j] = 1e6 - a[dd][i][j];
	}

	int ans = 0;
	for (int it = 0; it < 10; it++) {
		for (int i = 0; i < n; i++) p[i] = 0;
		for (int i = 0; i < n / 2; i++) p[i] = 1;
		random_shuffle(p, p + n);
		int o = 0;
		for (int i = 0; i < n; i++) if (p[i]) o += pw(i);

		int s = val(o);
		for (int i = 0; i < 1000; i++) {
			int x = rand() % n;
			int y = rand() % n;
			if (((o & pw(x)) > 0) && ((o & pw(y)) > 0)) {
				i--;
				continue;
			}
			if (((o & pw(x)) == 0) && ((o & pw(y)) == 0)) {
				i--;
				continue;
			}
			int oo = o ^ pw(x) ^ pw(y);
			int ss = val(oo);
			if (ss > s) {
				o = oo;
				s = ss;
			}
		}
		ans = max(ans, s);
	}

	cout << ans << endl;
	return 0;
}


#include<stdio.h>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<memory.h>
#include<map>
#include<set>
#include<queue>
#include<list>
#include<sstream>
#include<cstring>
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define SS stringstream
#define sqr(x) ((x)*(x))
#define m0(x) memset(x,0,sizeof(x))
#define m1(x) memset(x,63,sizeof(x))
#define CC(x) cout << (x) << endl
#define pw(x) (1ll<<(x))
#define buli(x) __builtin_popcountll(x)
#define forn(i, n) for(int i = 0 ; (i) < (n) ; ++i)
#define M 1000000007
#define N 211111

#define TASK "1"

using namespace std;
typedef pair<int,int> pt;

int n;
int a[2][22][22];

int S, T;
int yy[8888], cs[8888], xx[8888], pp[8888], fl[8888];
int f[8888], d[8888], ww[8888], pr[8888];
int kk;

void ae(int x, int y, int ff, int coco) {
	yy[++kk] = y;
	cs[kk] = coco;
	fl[kk] = ff;
	pp[kk] = xx[x];
 	xx[x] = kk;

	yy[++kk] = x;
	cs[kk] = -coco;
	fl[kk] = 0;
	pp[kk] = xx[y];
 	xx[y] = kk;

}

priority_queue<pair<int, int> > Q;

int main(){
//	freopen(TASK".in","r",stdin);
//	freopen(TASK".out","w",stdout);
	cin >> n;
	for (int dd = 0; dd < 2; dd++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
		cin >> a[dd][i][j];
		a[dd][i][j] = 1e6 - a[dd][i][j];
	}

	int ans = 0;
	for (int o = 0; o < pw(n); o++) {
		if (__builtin_popcount(o) != n / 2) continue;

		S = n + n;
		T = S + 1;
		for (int i = 0; i <= T; i++) xx[i] = 0;
		kk = 1;

		for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {
			int dd = 0;
			if (o & pw(j)) dd = 1;

			ae(i, j + n, 1, a[dd][i][j]);
		}
		for (int i = 0; i < n; i++) ae(S, i, 1, 0);
		for (int i = 0; i < n; i++) ae(i + n, T, 1, 0);

		for (int i = 0; i <= T; i++) {
			ww[i] = 0;
		}

		int cur = 0;
		for (int it = 0; it < n; it++) {
			for (int i = 0; i <= T; i++) {
				f[i] = 0;
				d[i] = 1e9;
			}
			d[S] = 0;
			while(Q.size() > 0) Q.pop();
			Q.push(mp(0, S));
			for (;;) {
				while (Q.size() > 0 && f[Q.top().S]) Q.pop();
				if (Q.size() == 0) break;
				int x = Q.top().S;
				f[x] = 1;
				for (int w = xx[x]; w; w = pp[w]) if (fl[w] > 0) {
					int to = yy[w];
					int dist = d[x] + cs[w] + ww[x] - ww[to];
					if (dist < d[to]) {
						d[to] = dist;
						pr[to] = w;
						Q.push(mp(-dist, to));
					}
				}
			}
			int x = T;
			while (x != S) {
				cur += cs[pr[x]];
				fl[pr[x]]--;
				fl[pr[x] ^ 1]++;
				x = yy[pr[x] ^ 1];
			}
			for (int i = 0; i <= T; i++) if (d[i] != 1e9) ww[i] += d[i];
		}
		ans = max(ans, 1000000 * n - cur);
	}
	cout << ans << endl;
	return 0;
}


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 205;
const int MAXEDGE = 20005;

typedef long long Type;
const Type INF = 0x3f3f3f3f3f3f3f;

struct Edge {
    int u, v;
    Type cap, flow, cost;
    Edge() {}
    Edge(int u, int v, Type cap, Type flow, Type cost) {
        this->u = u;
        this->v = v;
        this->cap = cap;
        this->flow = flow;
        this->cost = cost;
    }
};

struct MCFC {
    int n, m, s, t;
    Edge edges[MAXEDGE];
    int first[MAXNODE];
    int next[MAXEDGE];
    int inq[MAXNODE];
    Type d[MAXNODE];
    int p[MAXNODE];
    Type a[MAXNODE];

    void init(int n) {
        this->n = n;
        memset(first, -1, sizeof(first));
        m = 0;
    }

    void add_Edge(int u, int v, Type cap, Type cost) {
        edges[m] = Edge(u, v, cap, 0, cost);
        next[m] = first[u];
        first[u] = m++;
        edges[m] = Edge(v, u, 0, 0, -cost);
        next[m] = first[v];
        first[v] = m++;
    }

    bool bellmanford(int s, int t, Type &flow, Type &cost) {

        for (int i = 0; i < n; i++) d[i] = INF;
        memset(inq, false, sizeof(inq));
        d[s] = 0; inq[s] = true; p[s] = s; a[s] = INF;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = first[u]; i != -1; i = next[i]) {
                Edge& e = edges[i];
                if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
                    d[e.v] = d[u] + e.cost;
                    p[e.v] = i;
                    a[e.v] = min(a[u], e.cap - e.flow);
                    if (!inq[e.v]) {Q.push(e.v); inq[e.v] = true;}
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].u;
        }
        return true;
    }

    Type Mincost(int s, int t) {
        Type flow = 0, cost = 0;
        while (bellmanford(s, t, flow, cost));
        //printf("%d\n", flow);
        return cost;
    }
} gao;

int n;

int main() {
    while (~scanf("%d", &n)) {
        gao.init(5 * n + 4);
        Type x;
        gao.add_Edge(0, 1, n, 0);
        gao.add_Edge(0, 2, n, 0);
        for (int i = 1; i <= n; i++) {
            gao.add_Edge(1, i + 2, 1, 0);
            gao.add_Edge(2, i + 2, 1, 0);
            gao.add_Edge(i + 2, i + 2 + n, 1, 0);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%lld", &x);
                gao.add_Edge(i + 2 + n, j + 2 * n + 2, 1, -x);
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%lld", &x);
                gao.add_Edge(i + 2 + n, j + 3 * n + 2, 1, -x);
            }
        }
        for (int j = 1; j <= n; j++) {
            gao.add_Edge(j + 2 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 3 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 4 * n + 2, 5 * n + 3, 1, 0);
        }
        printf("%lld\n", -gao.Mincost(0, 5 * n + 3));
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 105;
const int MAXEDGE = 200005;
typedef int Type;
const Type INF = 0x3f3f3f3f;

struct Edge {
    int u, v;
    Type cap, flow, cost;
    Edge() {}
    Edge(int u, int v, Type cap, Type flow, Type cost) {
        this->u = u;
        this->v = v;
        this->cap = cap;
        this->flow = flow;
        this->cost = cost;
    }
};

struct MCFC {
    int n, m, s, t;
    Edge edges[MAXEDGE];
    int first[MAXNODE];
    int next[MAXEDGE];
    int inq[MAXNODE];
    Type d[MAXNODE];
    int p[MAXNODE];
    Type a[MAXNODE];

    void init(int n) {
        this->n = n;
        memset(first, -1, sizeof(first));
        m = 0;
    }

    void add_Edge(int u, int v, Type cap, Type cost) {
        edges[m] = Edge(u, v, cap, 0, cost);
        next[m] = first[u];
        first[u] = m++;
        edges[m] = Edge(v, u, 0, 0, -cost);
        next[m] = first[v];
        first[v] = m++;
    }

    bool bellmanford(int s, int t, Type &flow, Type &cost) {

        for (int i = 0; i < n; i++) d[i] = INF;
        memset(inq, false, sizeof(inq));
        d[s] = 0; inq[s] = true; p[s] = s; a[s] = INF;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = first[u]; i != -1; i = next[i]) {
                Edge& e = edges[i];
                if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
                    d[e.v] = d[u] + e.cost;
                    p[e.v] = i;
                    a[e.v] = min(a[u], e.cap - e.flow);
                    if (!inq[e.v]) {Q.push(e.v); inq[e.v] = true;}
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].u;
        }
        return true;
    }

    Type Mincost(int s, int t) {
        Type flow = 0, cost = 0;
        while (bellmanford(s, t, flow, cost));
        //printf("%d\n", flow);
        return cost;
    }
} gao;

int n;

int main() {
    while (~scanf("%d", &n)) {
        gao.init(5 * n + 4);
        int x;
        gao.add_Edge(0, 1, n, 0);
        gao.add_Edge(0, 2, n, 0);
        for (int i = 1; i <= n; i++) {
            gao.add_Edge(1, i + 2, 1, 0);
            gao.add_Edge(2, i + 2, 1, 0);
            gao.add_Edge(i + 2, i + 2 + n, 1, 0);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &x);
                gao.add_Edge(i + 2 + n, j + 2 * n + 2, 1, -x);
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &x);
                gao.add_Edge(i + 2 + n, j + 3 * n + 2, 1, -x);
            }
        }
        for (int j = 1; j <= n; j++) {
            gao.add_Edge(j + 2 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 3 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 4 * n + 2, 5 * n + 3, 1, 0);
        }
        printf("%d\n", -gao.Mincost(0, 5 * n + 3));
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 25;
const int INF = 0x3f3f3f3f;

int n, left[N][N], lx[N][N], ly[N][N], G[2][N][N], g[N][N], slack[N], use[N], pre[N];
int now;
int ans;

void km(int u) {
    now = u;
    for (int i = 0; i <= n; i++) {
        left[u][i] = left[u - 1][i];
        lx[u][i] = lx[u - 1][i];
        ly[u][i] = ly[u - 1][i];
        slack[i] = INF;
        use[i] = 0;
    }
    left[u][0] = now;
    int r = 0;
    while (left[u][r]) {
        use[r] = 1;
        int d = INF, v;
        for (int i = 1; i <= n; i++) {
            if (use[i]) continue;
            int tmp = lx[u][left[u][r]] + ly[u][i] - g[left[u][r]][i];
            if (tmp < slack[i]) {slack[i] = tmp; pre[i] = r;}
            if (slack[i] < d) {d = slack[i]; v = i;}
        }
        for (int i = 0; i <= n; i++) {
            if (use[i]) {lx[u][left[u][i]] -= d; ly[u][i] += d;}
            else slack[i] -= d;
        }
        r = v;
    }
    while (r) {
        left[u][r] = left[u][pre[r]];
        r = pre[r];
    }
}

void dfs(int u, int cnt) {
    if (u == n + 1) {
        int sum = 0;
        for (int i = 1; i <= n; i++) sum += lx[n][i] + ly[n][i];
        ans = max(ans, sum);
        return;
    }
    for (int i = 0; i < 2; i++) {
        if (cnt + i > n / 2 || (u - cnt - i) > n / 2) continue;
        for (int j = 1; j <= n; j++)
            g[u][j] = G[i][u][j];
        km(u);
        dfs(u + 1, cnt + i);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < 2; i++) {
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                scanf("%d", &G[i][j][k]);
    }
    dfs(1, 0);
    printf("%d\n", ans);
    return 0;
}


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 205;
const int MAXEDGE = 20005;

typedef long long Type;
const Type INF = 0x3f3f3f3f3f3f3f;

struct Edge {
    int u, v;
    Type cap, flow, cost;
    Edge() {}
    Edge(int u, int v, Type cap, Type flow, Type cost) {
        this->u = u;
        this->v = v;
        this->cap = cap;
        this->flow = flow;
        this->cost = cost;
    }
};

struct MCFC {
    int n, m, s, t;
    Edge edges[MAXEDGE];
    int first[MAXNODE];
    int next[MAXEDGE];
    int inq[MAXNODE];
    Type d[MAXNODE];
    int p[MAXNODE];
    Type a[MAXNODE];

    void init(int n) {
        this->n = n;
        memset(first, -1, sizeof(first));
        m = 0;
    }

    void add_Edge(int u, int v, Type cap, Type cost) {
        edges[m] = Edge(u, v, cap, 0, cost);
        next[m] = first[u];
        first[u] = m++;
        edges[m] = Edge(v, u, 0, 0, -cost);
        next[m] = first[v];
        first[v] = m++;
    }

    bool bellmanford(int s, int t, Type &flow, Type &cost) {

        for (int i = 0; i < n; i++) d[i] = INF;
        memset(inq, false, sizeof(inq));
        d[s] = 0; inq[s] = true; p[s] = s; a[s] = INF;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = first[u]; i != -1; i = next[i]) {
                Edge& e = edges[i];
                if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
                    d[e.v] = d[u] + e.cost;
                    p[e.v] = i;
                    a[e.v] = min(a[u], e.cap - e.flow);
                    if (!inq[e.v]) {Q.push(e.v); inq[e.v] = true;}
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].u;
        }
        return true;
    }

    Type Mincost(int s, int t) {
        Type flow = 0, cost = 0;
        while (bellmanford(s, t, flow, cost));
        //printf("%d\n", flow);
        return cost;
    }
} gao;

int n;

int main() {
    while (~scanf("%d", &n)) {
        gao.init(5 * n + 4);
        Type x;
        gao.add_Edge(0, 1, n / 2, 0);
        gao.add_Edge(0, 2, n / 2, 0);
        for (int i = 1; i <= n; i++) {
            gao.add_Edge(1, i + 2, 1, 0);
            gao.add_Edge(2, i + 2, 1, 0);
            gao.add_Edge(i + 2, i + 2 + n, 1, 0);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%lld", &x);
                gao.add_Edge(i + 2 + n, j + 2 * n + 2, 1, -x);
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%lld", &x);
                gao.add_Edge(i + 2 + n, j + 3 * n + 2, 1, -x);
            }
        }
        for (int j = 1; j <= n; j++) {
            gao.add_Edge(j + 2 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 3 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 4 * n + 2, 5 * n + 3, 1, 0);
        }
        printf("%lld\n", -gao.Mincost(0, 5 * n + 3));
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 25;
const int INF = 0x3f3f3f3f;
inline int lowbit(int x) {return x&(-x);}

int n, left[N][N], lx[N][N], ly[N][N], G[2][N][N], g[N][N], slack[N], S[N], T;
int now;
int ans, id[1<<20];

bool gao(int u) {
    S[u] = 1;
    int tt = T;
    while (tt&T) {
        int sb = lowbit(tt&T);
        int i = id[sb];
        tt ^= sb;
        int tmp = lx[now][u] + ly[now][i] - g[u][i];
        if (!tmp) {
            T ^= sb;
            if (!left[now][i] || gao(left[now][i])) {
                left[now][i] = u;
                return true;
            }
        } else slack[i] = min(slack[i], tmp);
    }
    return false;
}

void update() {
    int a = INF;
    for (int i = 1; i <= n; i++)
        if ((T>>(i - 1))&1) a = min(a, slack[i]);
    for (int i = 1; i <= n; i++) {
        if (S[i]) lx[now][i] -= a;
        if (!((T>>(i - 1))&1)) ly[now][i] += a;
    }
}

void km(int u) {
    now = u;
    for (int i = 1; i <= n; i++) {
        left[u][i] = left[u - 1][i];
        lx[u][i] = lx[u - 1][i];
        ly[u][i] = ly[u - 1][i];
        slack[i] = INF;
    }
    lx[u][u] = -INF;
    for (int i = 1; i <= n; i++)
        lx[u][u] = max(lx[u][u], g[u][i]);
    while (1) {
        memset(S, 0, sizeof(S));
        T = (1<<n) - 1;
        if (gao(u)) break;
        else update();
    }
}

void dfs(int u, int cnt) {
    if (u == n + 1) {
        int sum = 0;
        for (int i = 1; i <= n; i++) sum += lx[n][i] + ly[n][i];
        ans = max(ans, sum);
        return;
    }
    for (int i = 0; i < 2; i++) {
        if (cnt + i > n / 2 || (u - cnt - i) > n / 2) continue;
        for (int j = 1; j <= n; j++)
            g[u][j] = G[i][u][j];
        km(u);
        dfs(u + 1, cnt + i);
    }
}

int main() {

    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        id[1<<i] = i + 1;
    for (int i = 0; i < 2; i++) {
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                scanf("%d", &G[i][j][k]);
    }
    dfs(1, 0);
    printf("%d\n", ans);
    return 0;
}


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 205;
const int MAXEDGE = 20005;

typedef long long Type;
const Type INF = 0x3f3f3f3f3f3f3f;

struct Edge {
    int u, v;
    Type cap, flow, cost;
    Edge() {}
    Edge(int u, int v, Type cap, Type flow, Type cost) {
        this->u = u;
        this->v = v;
        this->cap = cap;
        this->flow = flow;
        this->cost = cost;
    }
};

struct MCFC {
    int n, m, s, t;
    Edge edges[MAXEDGE];
    int first[MAXNODE];
    int next[MAXEDGE];
    int inq[MAXNODE];
    Type d[MAXNODE];
    int p[MAXNODE];
    Type a[MAXNODE];

    void init(int n) {
        this->n = n;
        memset(first, -1, sizeof(first));
        m = 0;
    }

    void add_Edge(int u, int v, Type cap, Type cost) {
        edges[m] = Edge(u, v, cap, 0, cost);
        next[m] = first[u];
        first[u] = m++;
        edges[m] = Edge(v, u, 0, 0, -cost);
        next[m] = first[v];
        first[v] = m++;
    }

    bool bellmanford(int s, int t, Type &flow, Type &cost) {

        for (int i = 0; i < n; i++) d[i] = INF;
        memset(inq, false, sizeof(inq));
        d[s] = 0; inq[s] = true; p[s] = s; a[s] = INF;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = first[u]; i != -1; i = next[i]) {
                Edge& e = edges[i];
                if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
                    d[e.v] = d[u] + e.cost;
                    p[e.v] = i;
                    a[e.v] = min(a[u], e.cap - e.flow);
                    if (!inq[e.v]) {Q.push(e.v); inq[e.v] = true;}
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].u;
        }
        return true;
    }

    Type Mincost(int s, int t) {
        Type flow = 0, cost = 0;
        while (bellmanford(s, t, flow, cost));
        //printf("%d\n", flow);
        return cost;
    }
} gao;

int n, tmp[25], vis[25];
Type ans;
int g[2][25][25];

Type solve() {
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i < n / 2; i++) vis[tmp[i]] = 1;
    gao.init(2 * n + 2);
    for (int i = 1; i <= n; i++) {
        gao.add_Edge(0, i, 1, 0);
        gao.add_Edge(i + n, 2 * n + 1, 1, 0);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            gao.add_Edge(i, j + n, 1, -g[vis[i]][i][j]);
        }
    }
    return -gao.Mincost(0, 2 * n + 1);
}

void dfs(int u, int cnt) {
    if (cnt == n / 2) {
        ans =  max(ans, solve());
        return;
    }
    if (n - u + cnt < n / 2) return;
    if (u == n) return;
    tmp[cnt] = u;
    dfs(u + 1, cnt + 1);
    dfs(u + 1, cnt);
}

int main() {
    while (~scanf("%d", &n)) {
        ans = 0;
        for (int i = 0; i < 2; i++) {
            for (int x = 1; x <= n; x++) {
                for(int y = 1; y <= n; y++)
                    scanf("%d", &g[i][x][y]);
            }
        }
        dfs(0, 0);
        printf("%lld\n", ans);
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 205;
const int MAXEDGE = 20005;

typedef int Type;
const Type INF = 0x3f3f3f3f;

struct Edge {
    int u, v;
    Type cap, flow, cost;
    Edge() {}
    Edge(int u, int v, Type cap, Type flow, Type cost) {
        this->u = u;
        this->v = v;
        this->cap = cap;
        this->flow = flow;
        this->cost = cost;
    }
};

struct MCFC {
    int n, m, s, t;
    Edge edges[MAXEDGE];
    int first[MAXNODE];
    int next[MAXEDGE];
    int inq[MAXNODE];
    Type d[MAXNODE];
    int p[MAXNODE];
    Type a[MAXNODE];

    void init(int n) {
        this->n = n;
        memset(first, -1, sizeof(first));
        m = 0;
    }

    void add_Edge(int u, int v, Type cap, Type cost) {
        edges[m] = Edge(u, v, cap, 0, cost);
        next[m] = first[u];
        first[u] = m++;
        edges[m] = Edge(v, u, 0, 0, -cost);
        next[m] = first[v];
        first[v] = m++;
    }

    bool bellmanford(int s, int t, Type &flow, Type &cost) {

        for (int i = 0; i < n; i++) d[i] = INF;
        memset(inq, false, sizeof(inq));
        d[s] = 0; inq[s] = true; p[s] = s; a[s] = INF;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = false;
            for (int i = first[u]; i != -1; i = next[i]) {
                Edge& e = edges[i];
                if (e.cap > e.flow && d[e.v] > d[u] + e.cost) {
                    d[e.v] = d[u] + e.cost;
                    p[e.v] = i;
                    a[e.v] = min(a[u], e.cap - e.flow);
                    if (!inq[e.v]) {Q.push(e.v); inq[e.v] = true;}
                }
            }
        }
        if (d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].u;
        }
        return true;
    }

    Type Mincost(int s, int t) {
        Type flow = 0, cost = 0;
        while (bellmanford(s, t, flow, cost));
        //printf("%d\n", flow);
        return cost;
    }
} gao;

int n;

int main() {
    while (~scanf("%d", &n)) {
        gao.init(5 * n + 4);
        int x;
        gao.add_Edge(0, 1, n, 0);
        gao.add_Edge(0, 2, n, 0);
        for (int i = 1; i <= n; i++) {
            gao.add_Edge(1, i + 2, 1, 0);
            gao.add_Edge(2, i + 2, 1, 0);
            gao.add_Edge(i + 2, i + 2 + n, 1, 0);
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &x);
                gao.add_Edge(i + 2 + n, j + 2 * n + 2, 1, -x);
            }
        }
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                scanf("%d", &x);
                gao.add_Edge(i + 2 + n, j + 3 * n + 2, 1, -x);
            }
        }
        for (int j = 1; j <= n; j++) {
            gao.add_Edge(j + 2 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 3 * n + 2, j + 4 * n + 2, 1, 0);
            gao.add_Edge(j + 4 * n + 2, 5 * n + 3, 1, 0);
        }
        printf("%d\n", -gao.Mincost(0, 5 * n + 3));
    }
    return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=23;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool visx[N],visy[N];
int lx[N],ly[N],slack[N],pre[N],linkx[N],linky[N];

il void update() {
	int d=inf;
	for(int i=0;i<n;++i) if(!visy[i]) getmin(d,slack[i]);
	for(int i=0;i<n;++i){
		if(visx[i]) lx[i]-=d;
		if(visy[i]) ly[i]+=d;else slack[i]-=d;
	}
}

il void connect(int v) {
	while(~v) linky[v]=pre[v],swap(linkx[pre[v]],v);
}

int q[1005],st,ed;
il void bfs(int u) {
	st=0,ed=1,q[ed]=u,visx[u]=true;
	while(true){
		while(st<ed) {
			int u=q[++st];
			for(int v=0;v<n;++v){
				if(visy[v]) continue;
				int diff=lx[u]+ly[v]-g[u][v];
				if(diff>slack[v]) continue;
				pre[v]=u;
				if(!diff) {
					visy[v]=true;
					if(~linky[v]) q[++ed]=linky[v],visx[linky[v]]=true;
					else{connect(v);return;}
				}else{
					slack[v]=diff;
				}
			}
		}
		update();
		for(int v=0;v<n;++v) {
			if(!visy[v]&&!slack[v]) {
				visy[v]=true;
				if(~linky[v]) visx[linky[v]]=true,q[++ed]=linky[v];
				else {connect(v);return;}
			}
		}
	}
}

il int KM(){
	memset(linkx,-1,sizeof(int)*n);
	memset(linky,-1,sizeof(int)*n);
	memset(ly,0,sizeof(int)*n);
	for(int i=0;i<n;++i){
		lx[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(lx[i],g[i][j]);
	}
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) slack[j]=inf,visx[j]=visy[j]=false;
		bfs(i);
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=lx[i]+ly[i];
	return ans;
}

int main(){
//	fileio("data");
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=1;comb<(1<<n);++comb){
		if(__builtin_popcount(comb)!=k) continue;
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
	}
	printf("%d\n",ans);
//	cerr<<(dbl)clock()/CLOCKS_PER_SEC<<endl;
	return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=20;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool usedx[N],usedy[N];
int ex[N],ey[N],slack[N],match[N];

il bool dfs(int u){
	usedx[u]=true;
	for(int i=0;i<n;++i){
		if(usedy[i]) continue;
		int diff=ex[u]+ey[i]-g[u][i];
		if(!diff){
			usedy[i]=true;
			if(match[i]==-1||dfs(match[i])){
				match[i]=u;
				return true;
			}
		}else{
			getmin(slack[i],diff);
		}
	}
	return false;
}

il int KM(){
	memset(match,-1,sizeof(int)*n);
	memset(ey,0,sizeof(int)*n);
//	rep0(i,n){rep0(j,n) cerr<<g[i][j]<<" ";cerr<<endl;}
	for(int i=0;i<n;++i){
		ex[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(ex[i],g[i][j]);
	}
	for(int i=0;i<n;++i){
	//	cerr<<" "<<i<<endl;
		fill(slack,slack+n,inf);
		while(true){
			memset(usedx,false,sizeof(bool)*n);
			memset(usedy,false,sizeof(bool)*n);
			if(dfs(i)) break;
			int d=inf;
			for(int j=0;j<n;++j) if(!usedy[j]) getmin(d,slack[j]);
			for(int j=0;j<n;++j){
				if(usedx[j]) ex[j]-=d;
				if(usedy[j]) ey[j]+=d;else slack[j]-=d;
			}
		}
	//	cerr<<"match: ";
	//	for(int i=0;i<n;++i) cerr<<match[i]<<" ";cerr<<endl;
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=g[match[i]][i];
	return ans;
}

int main(){
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=(1<<k)-1,x,y,z;comb<(1<<n);x=comb&-comb,y=comb+x,z=comb&~y,comb=(z/x>>1)|y){
	//	cerr<<comb<<endl;
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
	}
	printf("%d\n",ans);
	return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=23;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool visx[N],visy[N];
int lx[N],ly[N],slack[N],pre[N],linkx[N],linky[N];

il void update() {
	int d=inf;
	for(int i=0;i<n;++i) if(!visy[i]) getmin(d,slack[i]);
	for(int i=0;i<n;++i){
		if(visx[i]) lx[i]-=d;
		if(visy[i]) ly[i]+=d;else slack[i]-=d;
	}
}

il void connect(int v) {
	while(~v) linky[v]=pre[v],swap(linkx[pre[v]],v);
}

int q[1005],st,ed;
il void bfs(int u) {
	st=0,ed=1,q[ed]=u,visx[u]=true;
	while(true){
		while(st<ed) {
			int u=q[++st];
			for(int v=0;v<n;++v){
				if(visy[v]) continue;
				int diff=lx[u]+ly[v]-g[u][v];
				if(diff>slack[v]) continue;
				pre[v]=u;
				if(!diff) {
					visy[v]=true;
					if(~linky[v]) q[++ed]=linky[v],visx[linky[v]]=true;
					else{connect(v);return;}
				}else{
					slack[v]=diff;
				}
			}
		}
		update();
		for(int v=0;v<n;++v) {
			if(!visy[v]&&!slack[v]) {
				visy[v]=true;
				if(~linky[v]) visx[linky[v]]=true,q[++ed]=linky[v];
				else {connect(v);return;}
			}
		}
	}
}

il int KM(){
	memset(linkx,-1,sizeof(int)*n);
	memset(linky,-1,sizeof(int)*n);
	for(int i=0;i<n;++i){
		ly[i]=0,lx[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(lx[i],g[i][j]);
	}
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) slack[j]=inf,visx[j]=visy[j]=false;
		bfs(i);
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=lx[i]+ly[i];
	return ans;
}

int main(){
//	fileio("data");
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=(1<<k)-1,x,y,z;comb<1<<n;x=comb&-comb,y=comb+x,z=comb&~y,comb=(z/x>>1)|y){
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
		if(clock()>1.7*CLOCKS_PER_SEC) return printf("%d\n",ans),0;
	}
	printf("%d\n",ans);
//	cerr<<(dbl)clock()/CLOCKS_PER_SEC<<endl;
	return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=22;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool visx[N],visy[N];
int lx[N],ly[N],slack[N],pre[N],linkx[N],linky[N];

il void update() {
	int d=inf;
	for(int i=0;i<n;++i) if(!visy[i]) getmin(d,slack[i]);
	for(int i=0;i<n;++i){
		if(visx[i]) lx[i]-=d;
		if(visy[i]) ly[i]+=d;else slack[i]-=d;
	}
}

il void connect(int v) {
	while(~v) linky[v]=pre[v],swap(linkx[pre[v]],v);
}

int q[1005],st,ed;
il void bfs(int u) {
	st=0,ed=1,q[ed]=u,visx[u]=true;
	while(true){
		while(st<ed) {
			int u=q[++st];
			for(int v=0;v<n;++v){
				if(visy[v]) continue;
				int diff=lx[u]+ly[v]-g[u][v];
				if(diff>slack[v]) continue;
				pre[v]=u;
				if(!diff) {
					visy[v]=true;
					if(~linky[v]==-1) q[++ed]=linky[v],visx[linky[v]]=true;
					else{connect(v);return;}
				}else{
					slack[v]=diff;
				}
			}
		}
		update();
		for(int v=0;v<n;++v) {
			if(!visy[v]&&!slack[v]) {
				visy[v]=true;
				if(~linky[v]) visx[linky[v]]=true,q[++ed]=linky[v];
				else {connect(v);return;}
			}
		}
	}
}

il int KM(){
	memset(linkx,-1,sizeof(int)*n);
	memset(linky,-1,sizeof(int)*n);
	memset(ly,0,sizeof(int)*n);
	for(int i=0;i<n;++i){
		lx[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(lx[i],g[i][j]);
	}
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) slack[j]=inf,visx[j]=visy[j]=false;
		bfs(i);
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=lx[i]+ly[i];
	return ans;
}

int main(){
//	fileio("data");
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=(1<<k)-1,x,y,z;comb<(1<<n);x=comb&-comb,y=comb+x,z=comb&~y,comb=(z/x>>1)|y){
	//	cerr<<comb<<endl;
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
	}
	printf("%d\n",ans);
//	cerr<<(dbl)clock()/CLOCKS_PER_SEC<<endl;
	return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=23;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool visx[N],visy[N];
int lx[N],ly[N],slack[N],pre[N],linkx[N],linky[N];

il void update() {
	int d=inf;
	for(int i=0;i<n;++i) if(!visy[i]) getmin(d,slack[i]);
	for(int i=0;i<n;++i){
		if(visx[i]) lx[i]-=d;
		if(visy[i]) ly[i]+=d;else slack[i]-=d;
	}
}

il void connect(int v) {
	while(~v) linky[v]=pre[v],swap(linkx[pre[v]],v);
}

int q[1005],st,ed;
il void bfs(int u) {
	st=0,ed=1,q[ed]=u,visx[u]=true;
	while(true){
		while(st<ed) {
			int u=q[++st];
			for(int v=0;v<n;++v){
				if(visy[v]) continue;
				int diff=lx[u]+ly[v]-g[u][v];
				if(diff>slack[v]) continue;
				pre[v]=u;
				if(!diff) {
					visy[v]=true;
					if(~linky[v]) q[++ed]=linky[v],visx[linky[v]]=true;
					else{connect(v);return;}
				}else{
					slack[v]=diff;
				}
			}
		}
		update();
		for(int v=0;v<n;++v) {
			if(!visy[v]&&!slack[v]) {
				visy[v]=true;
				if(~linky[v]) visx[linky[v]]=true,q[++ed]=linky[v];
				else {connect(v);return;}
			}
		}
	}
}

il int KM(){
	memset(linkx,-1,sizeof(int)*n);
	memset(linky,-1,sizeof(int)*n);
	for(int i=0;i<n;++i){
		ly[i]=0,lx[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(lx[i],g[i][j]);
	}
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) slack[j]=inf,visx[j]=visy[j]=false;
		bfs(i);
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=lx[i]+ly[i];
	return ans;
}

int main(){
//	fileio("data");
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=(1<<k)-1,x,y,z;comb<1<<n;x=comb&-comb,y=comb+x,z=comb&~y,comb=(z/x>>1)|y){
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
		if(clock()>1.8*CLOCKS_PER_SEC) return printf("%d\n",ans),0;
	}
	printf("%d\n",ans);
//	cerr<<(dbl)clock()/CLOCKS_PER_SEC<<endl;
	return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=23;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool visx[N],visy[N];
int lx[N],ly[N],slack[N],pre[N],linkx[N],linky[N];

il void update() {
	int d=inf;
	for(int i=0;i<n;++i) if(!visy[i]) getmin(d,slack[i]);
	for(int i=0;i<n;++i){
		if(visx[i]) lx[i]-=d;
		if(visy[i]) ly[i]+=d;else slack[i]-=d;
	}
}

il void connect(int v) {
	while(~v) linky[v]=pre[v],swap(linkx[pre[v]],v);
}

int q[1005],st,ed;
il void bfs(int u) {
	st=0,ed=1,q[ed]=u,visx[u]=true;
	while(true){
		while(st<ed) {
			int u=q[++st];
			for(int v=0;v<n;++v){
				if(visy[v]) continue;
				int diff=lx[u]+ly[v]-g[u][v];
				if(diff>slack[v]) continue;
				pre[v]=u;
				if(!diff) {
					visy[v]=true;
					if(~linky[v]) q[++ed]=linky[v],visx[linky[v]]=true;
					else{connect(v);return;}
				}else{
					slack[v]=diff;
				}
			}
		}
		update();
		for(int v=0;v<n;++v) {
			if(!visy[v]&&!slack[v]) {
				visy[v]=true;
				if(~linky[v]) visx[linky[v]]=true,q[++ed]=linky[v];
				else {connect(v);return;}
			}
		}
	}
}

il int KM(){
	memset(linkx,-1,sizeof(int)*n);
	memset(linky,-1,sizeof(int)*n);
	for(int i=0;i<n;++i){
		ly[i]=0,lx[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(lx[i],g[i][j]);
	}
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) slack[j]=inf,visx[j]=visy[j]=false;
		bfs(i);
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=lx[i]+ly[i];
	return ans;
}

int main(){
	fileio("data");
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=(1<<k)-1,x,y,z;comb<1<<n;x=comb&-comb,y=comb+x,z=comb&~y,comb=(z/x>>1)|y){
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
	}
	printf("%d\n",ans);
//	cerr<<(dbl)clock()/CLOCKS_PER_SEC<<endl;
	return 0;
}


#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <cassert>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <bitset>
#include <stack>
#include <iomanip>
#include <utility>
#include <functional>

using namespace std;

#define mp make_pair
#define pb push_back
#define pf push_front
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int (i)=0;(i)<(n);++(i))
#define rep(i,st,ed) for(register int (i)=(st);(i)<=(ed);++(i))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

template<typename T> inline T qmin(const T a,const T b) {return a<b?a:b;}
template<typename T> inline T qmax(const T a,const T b) {return a>b?a:b;}
template<typename T> inline void getmin(T &a,const T b) {if(a>b) a=b;}
template<typename T> inline void getmax(T &a,const T b) {if(a<b) a=b;}

inline void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=1e9+7;
const ll linf=1e17+7;
const int N=23;

int a[N][N],b[N][N],g[N][N];
int n,k;

bool visx[N],visy[N];
int lx[N],ly[N],slack[N],pre[N],linkx[N],linky[N];

il void update() {
	int d=inf;
	for(int i=0;i<n;++i) if(!visy[i]) getmin(d,slack[i]);
	for(int i=0;i<n;++i){
		if(visx[i]) lx[i]-=d;
		if(visy[i]) ly[i]+=d;else slack[i]-=d;
	}
}

il void connect(int v) {
	while(~v) linky[v]=pre[v],swap(linkx[pre[v]],v);
}

int q[1005],st,ed;
il void bfs(int u) {
	st=0,ed=1,q[ed]=u,visx[u]=true;
	while(true){
		while(st<ed) {
			int u=q[++st];
			for(int v=0;v<n;++v){
				if(visy[v]) continue;
				int diff=lx[u]+ly[v]-g[u][v];
				if(diff>slack[v]) continue;
				pre[v]=u;
				if(!diff) {
					visy[v]=true;
					if(~linky[v]) q[++ed]=linky[v],visx[linky[v]]=true;
					else{connect(v);return;}
				}else{
					slack[v]=diff;
				}
			}
		}
		update();
		for(int v=0;v<n;++v) {
			if(!visy[v]&&!slack[v]) {
				visy[v]=true;
				if(~linky[v]) visx[linky[v]]=true,q[++ed]=linky[v];
				else {connect(v);return;}
			}
		}
	}
}

il int KM(){
	memset(linkx,-1,sizeof(int)*n);
	memset(linky,-1,sizeof(int)*n);
	for(int i=0;i<n;++i){
		ly[i]=0,lx[i]=g[i][0];
		for(int j=1;j<n;++j) getmax(lx[i],g[i][j]);
	}
	for(int i=0;i<n;++i) {
		for(int j=0;j<n;++j) slack[j]=inf,visx[j]=visy[j]=false;
		bfs(i);
	}
	int ans=0;
	for(int i=0;i<n;++i) ans+=lx[i]+ly[i];
	return ans;
}

int main(){
//	fileio("data");
	scanf("%d",&n),k=n>>1;
	rep0(i,n) rep0(j,n) scanf("%d",a[i]+j);
	rep0(i,n) rep0(j,n) scanf("%d",b[i]+j);
	int ans=0;
	for(int comb=(1<<k)-1,x,y,z;comb<1<<n;x=comb&-comb,y=comb+x,z=comb&~y,comb=(z/x>>1)|y){
		for(int i=0;i<n;++i){
			if(comb>>i&1) memcpy(g[i],a[i],sizeof(int)*n);
			else memcpy(g[i],b[i],sizeof(int)*n);
		}
		getmax(ans,KM());
	}
	printf("%d\n",ans);
//	cerr<<(dbl)clock()/CLOCKS_PER_SEC<<endl;
	return 0;
}


#include <bits/stdc++.h>
#define MAXN 2105
#define INF 100000000

using namespace std;

int cost[MAXN][MAXN];
int n, max_match;
int lx[MAXN], ly[MAXN];
int xy[MAXN];
int yx[MAXN];
bool S[MAXN], T[MAXN];
int slack[MAXN];
int slackx[MAXN];
int prev[MAXN];
int q[MAXN];

void init_labels() {
	memset(lx, 0, sizeof lx);
	memset(ly, 0, sizeof ly);
	for (int x = 0; x < n; x++)
		for (int y = 0; y < n; y++) lx[x] = max(lx[x], cost[x][y]);
}

void update_labels() {
	int x, y, delta = INF;

	for (y = 0; y < n; y++)
		if (!T[y]) delta = min(delta, slack[y]);
	for (x = 0; x < n; x++)
		if (S[x]) lx[x] -= delta;
	for (y = 0; y < n; y++)
		if (T[y]) ly[y] += delta;
		else slack[y] -= delta;
}

void add_to_tree(int x, int prevx) {
	S[x] = true;
	prev[x] = prevx;
	for (int y = 0; y < n; y++)
		if (lx[x] + ly[y] - cost[x][y] < slack[y]) {
			slack[y] = lx[x] + ly[y] - cost[x][y];
			slackx[y] = x;
		}
}

void augment() {
	if (max_match == n) return;
	int x, y, root;
	int wr = 0, rd = 0;

	memset(S, 0, sizeof S);
	memset(T, 0, sizeof T);
	memset(prev, -1, sizeof prev);
	for (x = 0; x < n; x++)
		if (xy[x] == -1) break;
	q[wr++] = root = x;
	prev[x] = -2;
	S[x] = true;
	for (y = 0; y < n; y++) {
		slack[y] = lx[root] + ly[y] - cost[root][y];
		slackx[y] = root;
	}

	while (true) {
		while (rd < wr) {
			x = q[rd++];
			for (y = 0; y < n; y++)
				if (cost[x][y] == lx[x] + ly[y] && !T[y]) {
					if (yx[y] == -1) break;
					T[y] = true;
					q[wr++] = yx[y];
					add_to_tree(yx[y], x);
				}
			if (y < n) break;
		}
		if (y < n) break;
		update_labels();
		wr = rd = 0;
		for (y = 0; y < n; y++)
			if (!T[y] && !slack[y]) {
				if (yx[y] == -1) {
					x = slackx[y];
					break;
				} else {
					T[y] = true;
					if (!S[yx[y]]) {
						q[wr++] = yx[y];
						add_to_tree(yx[y], slackx[y]);
					}
				}
			}
		if (y < n) break;
	}

	if (y < n) {
		max_match++;
		for (int cx = x, cy = y, ty; cx != -2; cx = prev[cx], cy = ty) {
			ty = xy[cx];
			yx[cy] = cx;
			xy[cx] = cy;
		}
		augment();
	}
}

int hungarian() {
	int x, rlt;

	max_match = 0;
	memset(xy, -1, sizeof(xy));
	memset(yx, -1, sizeof(yx));
	init_labels();
	augment();
	for (rlt = x = 0; x < n; x++) rlt += cost[x][xy[x]];
    return rlt;
}

bool come[(1<<20)];
int a[21][21], b[21][21];
int ans;
int vis[21];

void solve(int x) {
    come[x] = 1;
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < n; i ++) vis[i] = (x & (1 << i));
    for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) if(vis[i]) cost[i][j] = a[i][j];else cost[i][j] = b[i][j];
    int result = hungarian();
    ans = max(ans, result);
    int st = x;
    while(1) {
        bool more = 0;
        for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) if(vis[i] && !vis[j]) {
            int en = st - (1 << i) + (1 << j);
            if(come[en]) continue;
            swap(vis[i], vis[j]);
            come[en] = 1;
            more = 1;
            int aa = xy[i], bb = xy[j];
            xy[i] = -1; xy[j] = -1;
            yx[aa] = -1; yx[bb] = -1;
            max_match = n - 2;
            lx[i] = lx[j] = INF;
            st = en;
            for(int k = 0; k < n; k ++) cost[i][k] = b[i][k];
            for(int k = 0; k < n; k ++) cost[j][k] = a[j][k];
            augment();
            int rlt = 0;
            for(int x = 0; x < n; x ++) rlt += cost[x][xy[x]];
            ans = max(ans, rlt);
            goto END;
        }
        END:;
        if(!more) break;
    }
}

int main() {
    ///freopen("1.in", "r", stdin);
    scanf("%d", &n);
    for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) scanf("%d", &a[i][j]);
    for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) scanf("%d", &b[i][j]);
    ans = 0;
    for(int i = 0; i < (1 << n); i ++) if(!come[i]){
        int x = __builtin_popcount(i);
        if(x * 2 != n) continue;
        solve(i);
    }
    printf("%d\n", ans);
}


#include <bits/stdc++.h>
#define MAXN 21
#define INF 100000000

using namespace std;

int cost[MAXN][MAXN];
int n, max_match;
int lx[MAXN], ly[MAXN];
int xy[MAXN];
int yx[MAXN];
bool S[MAXN], T[MAXN];
int slack[MAXN];
int slackx[MAXN];
int prev[MAXN];
int q[MAXN];

void init_labels() {
	memset(lx, 0, sizeof lx);
	memset(ly, 0, sizeof ly);
	for (int x = 0; x < n; x++)
		for (int y = 0; y < n; y++) lx[x] = max(lx[x], cost[x][y]);
}

void update_labels() {
	int x, y, delta = INF;

	for (y = 0; y < n; y++)
		if (!T[y]) delta = min(delta, slack[y]);
	for (x = 0; x < n; x++)
		if (S[x]) lx[x] -= delta;
	for (y = 0; y < n; y++)
		if (T[y]) ly[y] += delta;
		else slack[y] -= delta;
}

void add_to_tree(int x, int prevx) {
	S[x] = true;
	prev[x] = prevx;
	for (int y = 0; y < n; y++)
		if (lx[x] + ly[y] - cost[x][y] < slack[y]) {
			slack[y] = lx[x] + ly[y] - cost[x][y];
			slackx[y] = x;
		}
}

void augment() {
	if (max_match == n) return;
	int x, y, root;
	int wr = 0, rd = 0;

	memset(S, 0, sizeof S);
	memset(T, 0, sizeof T);
	memset(prev, -1, sizeof prev);
	for (x = 0; x < n; x++)
		if (xy[x] == -1) break;
	q[wr++] = root = x;
	prev[x] = -2;
	S[x] = true;
	for (y = 0; y < n; y++) {
		slack[y] = lx[root] + ly[y] - cost[root][y];
		slackx[y] = root;
	}

	while (true) {
		while (rd < wr) {
			x = q[rd++];
			for (y = 0; y < n; y++)
				if (cost[x][y] == lx[x] + ly[y] && !T[y]) {
					if (yx[y] == -1) break;
					T[y] = true;
					q[wr++] = yx[y];
					add_to_tree(yx[y], x);
				}
			if (y < n) break;
		}
		if (y < n) break;
		update_labels();
		wr = rd = 0;
		for (y = 0; y < n; y++)
			if (!T[y] && !slack[y]) {
				if (yx[y] == -1) {
					x = slackx[y];
					break;
				} else {
					T[y] = true;
					if (!S[yx[y]]) {
						q[wr++] = yx[y];
						add_to_tree(yx[y], slackx[y]);
					}
				}
			}
		if (y < n) break;
	}

	if (y < n) {
		max_match++;
		for (int cx = x, cy = y, ty; cx != -2; cx = prev[cx], cy = ty) {
			ty = xy[cx];
			yx[cy] = cx;
			xy[cx] = cy;
		}
		augment();
	}
}

int hungarian() {
	int x, rlt;

	max_match = 0;
	memset(xy, -1, sizeof(xy));
	memset(yx, -1, sizeof(yx));
	init_labels();
	augment();
	for (rlt = x = 0; x < n; x++) rlt += cost[x][xy[x]];
    return rlt;
}

bool come[(1<<20)];
int a[21][21], b[21][21];
int ans;
int vis[21];

void solve(int x) {
    come[x] = 1;
    memset(vis, 0, sizeof(vis));
    for(int i = 0; i < n; i ++) vis[i] = (x & (1 << i));
    for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) if(vis[i]) cost[i][j] = a[i][j];else cost[i][j] = b[i][j];
    int result = hungarian();
    ans = max(ans, result);
    int st = x;
    while(1) {
        bool more = 0;
        for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) if(vis[i] && !vis[j]) {
            int en = st - (1 << i) + (1 << j);
            if(come[en]) continue;
            swap(vis[i], vis[j]);
            come[en] = 1;
            more = 1;
            int aa = xy[i], bb = xy[j];
            xy[i] = -1; xy[j] = -1;
            yx[aa] = -1; yx[bb] = -1;
            max_match = n - 2;
            lx[i] = lx[j] = INF;
            st = en;
            for(int k = 0; k < n; k ++) cost[i][k] = b[i][k];
            for(int k = 0; k < n; k ++) cost[j][k] = a[j][k];
            augment();
            int rlt = 0;
            for(int x = 0; x < n; x ++) rlt += cost[x][xy[x]];
            ans = max(ans, rlt);
            goto END;
        }
        END:;
        if(!more) break;
    }
}

int main() {
    ///freopen("1.in", "r", stdin);
    scanf("%d", &n);
    for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) scanf("%d", &a[i][j]);
    for(int i = 0; i < n; i ++) for(int j = 0; j < n; j ++) scanf("%d", &b[i][j]);
    ans = 0;
    for(int i = 0; i < (1 << n); i ++) if(!come[i]){
        int x = __builtin_popcount(i);
        if(x * 2 != n) continue;
        solve(i);
    }
    printf("%d\n", ans);
}