#include <bits/stdc++.h>
using namespace std;
#define MAXN 21
#define INF 1e9

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 ans;

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;
}

int vis[21], a[21][21], b[21][21], nn;
int suma[21], sumb[21], id[21];
int A[190000];
bool com[190001];
int cnt;

int calc(int bit) {
    n = nn;
    for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) if(vis[i]) cost[i][j] = a[i][j]; else cost[i][j] = b[i][j];
    int result = hungarian();
    bool more = 1;
    while(more) {
        more = 0;
        for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) if(vis[i] && !vis[j]) {
            int x = xy[i], y = xy[j];
            if(a[i][x] + b[j][y] < b[i][x] + a[j][y]) {
                swap(vis[i], vis[j]);
                more = 1;
                result += (a[j][y] + b[i][x] - a[i][x] - b[j][y]);
                return result;
                break;
            }
            if(a[i][x] + b[j][y] < b[i][y] + a[j][x]) {
                swap(vis[i], vis[j]);
                more = 1;
                result += (b[i][y] + a[j][x] - a[i][x] - b[j][y]);
                xy[i] = y;
                xy[j] = x;
                return result;
                break;
            }
        }
        break;
    }
    return result;
}

int main() {
    //freopen("1.in", "r", stdin);
    while(scanf("%d", &nn) > 0) {
        double start = clock();
        for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) scanf("%d", &a[i][j]);
        for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) scanf("%d", &b[i][j]);
        ans = 0;
        cnt = 0;
        for(int i = 0; i < (1 << nn); i ++) {
            int x = __builtin_popcount(i);
            if(x * 2 != nn) continue;
            A[cnt ++] = i;
        }
        while(clock() - start < 1900) {
            int x = 1ll * rand() * rand() % cnt;
            if(com[x]) continue;
            com[x] = 1;
            memset(vis, 0, sizeof(vis));
            for(int j = 0; j < nn; j ++) if(A[x] & (1 << j)) vis[j] = 1;
            ans = max(ans, calc(A[x]));
        }
        printf("%d\n", ans);
    }
}


#include <bits/stdc++.h>
using namespace std;
#define MAXN 21
#define INF 1e9

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 ans;

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;
}

int vis[21], a[21][21], b[21][21], nn;
int suma[21], sumb[21], id[21];
int A[300000], com[300001], cnt;

int calc(int bit) {
    n = nn;
    for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) if(vis[i]) cost[i][j] = a[i][j]; else cost[i][j] = b[i][j];
    int result = hungarian();
    bool more = 1;
    while(more) {
        more = 0;
        for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) if(vis[i] && !vis[j]) {
            int x = xy[i], y = xy[j];
            if(a[i][x] + b[j][y] < b[i][x] + a[j][y]) {
                swap(vis[i], vis[j]);
                more = 1;
                result += (a[j][y] + b[i][x] - a[i][x] - b[j][y]);
                return result;
                break;
            }
            if(a[i][x] + b[j][y] < b[i][y] + a[j][x]) {
                swap(vis[i], vis[j]);
                more = 1;
                result += (b[i][y] + a[j][x] - a[i][x] - b[j][y]);
                xy[i] = y;
                xy[j] = x;
                return result;
                break;
            }
        }
        break;
    }
    return result;
}

int main() {
    //freopen("1.in", "r", stdin);
    while(scanf("%d", &nn) > 0) {
        double start = clock();
        for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) scanf("%d", &a[i][j]);
        for(int i = 0; i < nn; i ++) for(int j = 0; j < nn; j ++) scanf("%d", &b[i][j]);
        ans = 0;
        cnt = 0;
        for(int i = 0; i < (1 << nn); i ++) {
            int x = __builtin_popcount(i);
            if(x * 2 != nn) continue;
            A[cnt ++] = i;
        }
        int gas = 0;
        while(clock() - start < 1900) {
            int x = 1ll * rand() * rand() % cnt;
            if(com[x]) continue;
            ++gas;
            com[x] = 1;
            memset(vis, 0, sizeof(vis));
            for(int j = 0; j < nn; j ++) if(A[x] & (1 << j)) vis[j] = 1;
            ans = max(ans, calc(A[x]));
        }
        printf("%d\n", ans);
    }
}


#include <bits/stdc++.h>
using namespace std;
#define MAXN 22
#define INF 1e9
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;
}

int a[MAXN][MAXN], b[MAXN][MAXN];

int main() {
//freopen("C.in", "r", stdin);
	int ans = 0;
	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]);
	}
	for (int i = 0; i < (1 << n); i++) {
		if (__builtin_popcount(i) != (n / 2)) continue;
		int m = 0, tmp = 0;
		memset(cost, 0, sizeof(cost));
		for (int j = 0; j < n; j++) {
			if (i & (1 << j)) {
				for (int k = 0; k < n; k++) cost[j][k] = a[j][k];
			}
		}

		tmp += hungarian();

		memset(cost, 0, sizeof(cost));
		for (int j = 0; j < n; j++) {
			if (!(i & (1 << j))) {
				for (int k = 0; k < n; k++) cost[j][k] = b[j][k];
			}
		}
		tmp += hungarian();
		if (tmp > ans) ans = tmp;
	}
	printf("%d\n", ans);
	return 0;
}


#include<stdio.h>
#include<algorithm>
#include<queue>
#include<memory.h>
#define MAXN 3000
#define INF 100000000
using namespace std;

queue<int> q1;

int w[MAXN][MAXN];
int n, M;
int u[MAXN], v[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(u, 0, sizeof(u));
	memset(v, 0, sizeof(v));
	for (int x = 0; x < n; x++)
	for (int y = 0; y < n; y++) u[x] = max(u[x], w[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]) u[x] -= delta;
	for (y = 0; y < n; y++)if (T[y]) v[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 (u[x] + v[y] - w[x][y] < slack[y]) {
			slack[y] = u[x] + v[y]  - w[x][y];
			slackx[y] = x;
		}

}

void add_match(int a, int b){
	int cx= a;
	int cy = b;
	while(1){
		int yy = xy[cx];
		xy[cx] = cy;
		yx[cy] = cx;
		if(prev[cx] == -2)break;
		int xx = prev[cx];
		cy = yy;
		cx = xx;
	}
	return ;
}

void augment() {
	if (M == n) return;
	//printf("%d\n", M);
	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;
	while(!q1.empty())q1.pop();
	root = x;
	q1.push(root);
	prev[x] = -2;
	S[x] = true;
	for (y = 0; y < n; y++) {
		slack[y] = u[root] + v[y]  - w[root][y];
		slackx[y] = root;
	}
	while (true) {
		while(!q1.empty()){
			x = q1.front();
			q1.pop();
			for (y = 0; y < n; y++)
			if (w[x][y] == u[x] + v[y] && !T[y]) {
				if (yx[y] == -1) break;
				T[y] = true;
				q1.push(yx[y]);
				add_to_tree(yx[y], x);
			}
			if (y < n) {
				break;
			}
		}
		if(y<n)break;
		update_labels();
		while(!q1.empty())q1.pop();
		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]]) {
						q1.push(yx[y]);
						add_to_tree(yx[y], slackx[y]);
					}
				}
			}
		if(y<n){
			break;
		}
	}
	if(y<n){
		M++;
		add_match(x, y);
		augment();
	}
	return ;
}
#define N 30
int Fri[N][N], Sat[N][N], A[N], C[N], B[N];

int ans;

void doit(int *A, int *B, int num){
    for(int i=0; i<num; i++)C[i] = xy[A[i]], C[i+num] = xy[B[i]];
    for(int i=0; i<num; i++)for(int j=0; j<n; j++)w[A[i]][j] = Sat[A[i]][j];
    for(int i=0; i<num; i++)for(int j=0; j<n; j++)w[B[i]][j] = Fri[B[i]][j];
    for(int i=0; i<num*2; i++)yx[C[i]] = -1;
    for(int i=0; i<num; i++)xy[A[i]]=-1, xy[B[i]] = -1;
    M-=2*num;
    for(int i=0; i<num; i++)u[A[i]] = 0, u[B[i]] = 0;
    for(int i=0; i<num; i++)for(int j=0; j<n; j++)u[A[i]] = max(u[A[i]], w[A[i]][j]), u[B[i]] = max(u[B[i]], w[B[i]][j]);
    augment();
    int ans1 = 0;
    for(int j=0; j<n; j++)ans1+=u[j]+v[j];
    ans = max(ans, ans1);
    return ;
}

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", &Fri[i][j]);
	for(int i=0; i<n; i++)for(int j=0; j<n; j++)scanf("%d", &Sat[i][j]);
	int m = n/2;
	for(int i=0; i<m; i++)for(int j=0; j<n; j++)w[i][j] = Fri[i][j];
	for(int i=m+1; i<n; i++)for(int j=0; j<n; j++)w[i][j] = Sat[i][j];
	for(int i=0; i<n; i++)u[i] =0;
	for(int i=0; i<n; i++){
		v[i] = 0;
		for(int j=0; j<n; j++)v[i] = max(v[i], w[j][i]);
	}
	for(int i=0; i<n; i++)xy[i] = -1;
	for(int i=0; i<n; i++)yx[i] = -1;
	M = 0;
	augment();
	ans = 0;
	for(int i=0; i<n; i++)ans += u[i]+v[i];
	int x = (1<<m) -1;
	int X = 0;
    for(int i=(1<<m); i<(1<<n); i++){
        int cnt = 0;
        for(int j=0; j<n; j++)if((i>>j)&1)A[cnt++] = j;
        if(cnt!=m)continue;
        int cnt1 = 0;
        int cnt2 = 0;
        for(int j=0; j<n; j++){
            if(((i>>j)&1) && !((x>>j)&1))A[cnt1++] = j;
            else if(!((i>>j)&1) && ((x>>j)&1))B[cnt2++] = j;
        }
        X+=cnt1;
        doit(B, A, cnt1);
        x = i;
    }
    //fprintf(stderr, "%d\n", X);
	printf("%d\n", ans);
	return 0;
}


#include<stdio.h>
#include<algorithm>
#include<queue>
#include<memory.h>
#define MAXN 30
#define INF 100000000
using namespace std;

queue<int> q1;

int w[MAXN][MAXN];
int n, M;
int u[MAXN], v[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(u, 0, sizeof(u));
	memset(v, 0, sizeof(v));
	for (int x = 0; x < n; x++)
	for (int y = 0; y < n; y++) u[x] = max(u[x], w[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]) u[x] -= delta;
	for (y = 0; y < n; y++)if (T[y]) v[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 (u[x] + v[y] - w[x][y] < slack[y]) {
			slack[y] = u[x] + v[y]  - w[x][y];
			slackx[y] = x;
		}

}

void add_match(int a, int b){
	int cx= a;
	int cy = b;
	while(1){
		int yy = xy[cx];
		xy[cx] = cy;
		yx[cy] = cx;
		if(prev[cx] == -2)break;
		int xx = prev[cx];
		cy = yy;
		cx = xx;
	}
	return ;
}

void augment() {
	if (M == n) return;
	//printf("%d\n", M);
	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;
	while(!q1.empty())q1.pop();
	root = x;
	q1.push(root);
	prev[x] = -2;
	S[x] = true;
	for (y = 0; y < n; y++) {
		slack[y] = u[root] + v[y]  - w[root][y];
		slackx[y] = root;
	}
	while (true) {
		while(!q1.empty()){
			x = q1.front();
			q1.pop();
			for (y = 0; y < n; y++)
			if (w[x][y] == u[x] + v[y] && !T[y]) {
				if (yx[y] == -1) break;
				T[y] = true;
				q1.push(yx[y]);
				add_to_tree(yx[y], x);
			}
			if (y < n) {
				break;
			}
		}
		if(y<n)break;
		update_labels();
		while(!q1.empty())q1.pop();
		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]]) {
						q1.push(yx[y]);
						add_to_tree(yx[y], slackx[y]);
					}
				}
			}
		if(y<n){
			break;
		}
	}
	if(y<n){
		M++;
		add_match(x, y);
		augment();
	}
	return ;
}
#define N 30
int Fri[N][N], Sat[N][N], A[N], C[N], B[N];

int ans;

void doit(int *A, int *B, int num){
    for(int i=0; i<num; i++)C[i] = xy[A[i]], C[i+num] = xy[B[i]];
    for(int i=0; i<num; i++)for(int j=0; j<n; j++)w[A[i]][j] = Sat[A[i]][j];
    for(int i=0; i<num; i++)for(int j=0; j<n; j++)w[B[i]][j] = Fri[B[i]][j];
    for(int i=0; i<num*2; i++)yx[C[i]] = -1;
    for(int i=0; i<num; i++)xy[A[i]]=-1, xy[B[i]] = -1;
    M-=2*num;
    for(int i=0; i<num; i++)u[A[i]] = 0, u[B[i]] = 0;
    for(int i=0; i<num; i++)for(int j=0; j<n; j++)u[A[i]] = max(u[A[i]], w[A[i]][j]), u[B[i]] = max(u[B[i]], w[B[i]][j]);
    augment();
    int ans1 = 0;
    for(int j=0; j<n; j++)ans1+=u[j]+v[j];
    ans = max(ans, ans1);
    return ;
}

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", &Fri[i][j]);
	for(int i=0; i<n; i++)for(int j=0; j<n; j++)scanf("%d", &Sat[i][j]);
	int m = n/2;
	for(int i=0; i<m; i++)for(int j=0; j<n; j++)w[i][j] = Fri[i][j];
	for(int i=m+1; i<n; i++)for(int j=0; j<n; j++)w[i][j] = Sat[i][j];
	for(int i=0; i<n; i++)u[i] =0;
	for(int i=0; i<n; i++){
		v[i] = 0;
		for(int j=0; j<n; j++)v[i] = max(v[i], w[j][i]);
	}
	for(int i=0; i<n; i++)xy[i] = -1;
	for(int i=0; i<n; i++)yx[i] = -1;
	M = 0;
	augment();
	ans = 0;
	for(int i=0; i<n; i++)ans += u[i]+v[i];
	int x = (1<<m) -1;
	int X = 0;
    for(int i=(1<<m); i<(1<<n); i++){
        int cnt = 0;
        for(int j=0; j<n; j++)if((i>>j)&1)A[cnt++] = j;
        if(cnt!=m)continue;
        int cnt1 = 0;
        int cnt2 = 0;
        for(int j=0; j<n; j++){
            if(((i>>j)&1) && !((x>>j)&1))A[cnt1++] = j;
            else if(!((i>>j)&1) && ((x>>j)&1))B[cnt2++] = j;
        }
        X+=cnt1;
        doit(B, A, cnt1);
        x = i;
    }
    //fprintf(stderr, "%d\n", X);
	printf("%d\n", ans);
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 0x3f3f3f3f

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

int n;
int A[M], B[M], lk[M], way[M], mn[M];
int w[M][M];
int a[M][M], b[M][M];
bool vis[M];
int ans;

inline void km(int x){
	lk[0] = x;
	int j0 = 0;
	memset(vis, 0, sizeof(vis));
	memset(mn, 0x3f, sizeof(mn));
	do{
		vis[j0] = true;
		int i0 = lk[j0], num = inf, j1;
		for(int j = 1; j <= n; j ++){
			if(!vis[j]){
				int t = -w[i0][j] + A[i0] + B[j];
				if(t < mn[j]) mn[j] = t, way[j] = j0;
				if(mn[j] < num) num = mn[j], j1 = j;
			}
		}
		for(int j = 0; j <= n; j ++){
			if(vis[j]) A[lk[j]] -= num, B[j] += num;
			else mn[j] -= num;
		}
		j0 = j1;
	} while(~lk[j0]);
	do{
		int j1 = way[j0];
		lk[j0] = lk[j1];
		j0 = j1;
	} while(j0);
}

inline void dfs(int x, int t){
	if(x == n + 1){
		ans = max(ans, -B[0]);
		return;
	}
	int oA[M], oB[M], m;
	if(t == (n >> 1)){
		for(int i = 1; i <= n; i ++) w[x][i] = a[x][i];
		km(x);
		dfs(x + 1, t);
		for(int i = 1; i <= n; i ++) w[x][i] = 0;
	}
	else if(x - t - 1 == (n >> 1)){
		for(int i = 1; i <= n; i ++) w[x][i] = b[x][i];
		km(x);
		dfs(x + 1, t + 1);
		for(int i = 1; i <= n; i ++) w[x][i] = 0;
	}
	else{
		int oa[M], ob[M], olk[M], oway[M];
		memcpy(oa, A, sizeof(A));
		memcpy(ob, B, sizeof(B));
		memcpy(olk, lk, sizeof(lk));
		memcpy(oway, way, sizeof(way));
		for(int i = 1; i <= n; i ++) w[x][i] = a[x][i];
		km(x);
		dfs(x + 1, t);
		for(int i = 1; i <= n; i ++) w[x][i] = 0;
		memcpy(A, oa, sizeof(oa));
		memcpy(B, ob, sizeof(ob));
		memcpy(lk, olk, sizeof(olk));
		memcpy(way, oway, sizeof(oway));
		for(int i = 1; i <= n; i ++) w[x][i] = b[x][i];
		km(x);
		dfs(x + 1, t + 1);
		for(int i = 1; i <= n; i ++) w[x][i] = 0;
	}
}

int main(){
	//freopen("0input.in", "r", stdin);
	n = read();
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	memset(lk, -1, sizeof(lk));
	dfs(1, 0);
	printf("%d\n", ans);
	return 0;
}


#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;
	int ans;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				int res = 0;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
					res += A[j];
					res += B[j];
				}
				if(res < ans) return;
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int start = clock();
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot;
	for(int i = (1 << n) - 1; i >= 0; i --){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
				else{
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::ans = max(KM::ans, res);
		//	if(clock() - start > 1970) break;
		}
	}
	printf("%d\n", KM::ans);
	return 0;
}


#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;
	int ans;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				int res = 0;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
					res += A[j];
					res += B[j];
				}
				if(res < ans) return;
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int start = clock();
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot;
	for(int i = (1 << n) - 1; i >= 0; i --){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
				else{
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::ans = max(KM::ans, res);
			if(clock() - start > 1970) break;
		}
	}
	printf("%d\n", KM::ans);
	return 0;
}


#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
				}
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int start = clock();
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot, ans = 0;
	for(int i = 0; i < 1 << n; i ++){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(!(i & (1 << j))){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			res += KM::getsum();
			ans = max(ans, res);
			if(clock() - start > 1970) break;
		}
	}
	printf("%d\n", ans);
	return 0;
}


#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
				}
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int start = clock();
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot, ans = 0;
	for(int i = 0; i < 1 << n; i ++){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(!(i & (1 << j))){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			res += KM::getsum();
			ans = max(ans, res);
			if(clock() - start > 1950) break;
		}
	}
	printf("%d\n", ans);
	return 0;
}


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

const int N = 20 + 1;

int n;

int a[2][N][N];

int ans;

int w[N][N], u[N][N], v[N][N], p[N][N];

const int INF = 1000000000;

int minv[N], fa[N];

bool used[N];

void km(int lev) {
	int i = lev;
	lev++;
	for (int j = 0; j <= n; ++j) {
		u[lev][j] = u[i][j];
		v[lev][j] = v[i][j];
		p[lev][j] = p[i][j];
		minv[j] = INF;
		used[j] = false;
	}
	p[lev][n] = i;
	int j0 = n;
	do {
		used[j0] = true;
		int i0 = p[lev][j0], delta = INF, j1;
		for (int j = 0; j < n; ++j) {
			if (!used[j]) {

				int cur = w[i0][j] - u[lev][i0] - v[lev][j];
				if (cur < minv[j]) {
					minv[j] = cur;
					fa[j] = j0;
				}
				if (minv[j] < delta) {
					delta = minv[j];
					j1 = j;
				}
			}
		}
		for (int j = 0; j <= n; ++j) {
			if (used[j]) {
				u[lev][p[lev][j]] += delta, v[lev][j] -= delta;
			} else {
				minv[j] -= delta;
			}
		}
		j0 = j1;
	} while (p[lev][j0] != -1);
	do {
		int j1 = fa[j0];
		p[lev][j0] = p[lev][j1];
		j0 = j1;
	} while (j0 != n);
}

void go(int i, int cnt) {
	if (i == n) {
		ans = max(ans, v[i][n]);
		return;
	}
	for (int c = 0; c < 2; ++c) {
		int ncnt = cnt + c;
		if ((ncnt << 1) <= n && ((i + 1 - ncnt) << 1) <= n) {
			for (int j = 0; j < n; ++j) {
				w[i][j] = a[c][i][j];
			}
			km(i);
			for (int j = 0; j < n; ++j) {
				w[i][j] = 0;
			}
			go(i + 1, ncnt);
		}
	}
}

int main() {
	scanf("%d", &n);
	for (int c = 0; c < 2; ++c) {
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				scanf("%d", &a[c][i][j]);
				a[c][i][j] = -a[c][i][j];
			}
		}
	}
	ans = 0;
	for (int i = 0; i < n; ++i) {
		p[0][i] = -1;
	}
	go(0, 0);
	printf("%d\n", ans);
	return 0;
}


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

const int N = 20 + 1;

int n;

int a[2][N][N];

int ans;

int w[N][N], u[N][N], v[N][N], p[N][N];

const int INF = 1000000000;

int minv[N], fa[N];

bool used[N];

void km(int lev) {
	int i = lev;
	lev++;
	for (int j = 0; j <= n; ++j) {
		u[lev][j] = u[i][j];
		v[lev][j] = v[i][j];
		p[lev][j] = p[i][j];
		minv[j] = INF;
		used[j] = false;
	}
	p[lev][n] = i;
	int j0 = n;
	do {
		used[j0] = true;
		int i0 = p[lev][j0], delta = INF, j1;
		for (int j = 0; j < n; ++j) {
			if (!used[j]) {
				int cur = w[i0][j] - u[lev][i0] - v[lev][j];
				if (cur < minv[j]) {
					minv[j] = cur;
					fa[j] = j0;
				}
				if (minv[j] < delta) {
					delta = minv[j];
					j1 = j;
				}
			}
		}
		for (int j = 0; j <= n; ++j) {
			if (used[j]) {
				u[lev][p[lev][j]] += delta, v[lev][j] -= delta;
			} else {
				minv[j] -= delta;
			}
		}
		j0 = j1;
	} while (p[lev][j0] != -1);
	do {
		int j1 = fa[j0];
		p[lev][j0] = p[lev][j1];
		j0 = j1;
	} while (j0 != n);
}

void go(int i, int cnt) {
	if (i == n) {
		ans = max(ans, v[i][n]);
		return;
	}
	for (int c = 0; c < 2; ++c) {
		int ncnt = cnt + c;
		if ((ncnt << 1) <= n && ((i + 1 - ncnt) << 1) <= n) {
			for (int j = 0; j < n; ++j) {
				w[i][j] = a[c][i][j];
			}
			km(i);
			go(i + 1, ncnt);
		}
	}
}

int main() {
	scanf("%d", &n);
	for (int c = 0; c < 2; ++c) {
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				scanf("%d", &a[c][i][j]);
				a[c][i][j] = -a[c][i][j];
			}
		}
	}
	ans = 0;
	for (int i = 0; i < n; ++i) {
		p[0][i] = -1;
	}
	go(0, 0);
	printf("%d\n", ans);
	return 0;
}


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

const int N = 20 + 1;

int n;

int a[2][N][N];

int ans;

int w[N][N], u[N][N], v[N][N], p[N][N];

const int INF = 1000000000;

int minv[N], fa[N];

bool used[N];

void km(int lev) {
	int i = lev;
	lev++;
	for (int j = 0; j <= n; ++j) {
		u[lev][j] = u[i][j];
		v[lev][j] = v[i][j];
		p[lev][j] = p[i][j];
		minv[j] = INF;
		used[j] = false;
	}
	p[lev][n] = i;
	int j0 = n;
	do {
		used[j0] = true;
		int i0 = p[lev][j0], delta = INF, j1;
		for (int j = 0; j < n; ++j) {
			if (!used[j]) {

				int cur = w[i0][j] - u[lev][i0] - v[lev][j];
				if (cur < minv[j]) {
					minv[j] = cur;
					fa[j] = j0;
				}
				if (minv[j] < delta) {
					delta = minv[j];
					j1 = j;
				}
			}
		}
		for (int j = 0; j <= n; ++j) {
			if (used[j]) {
				u[lev][p[lev][j]] += delta, v[lev][j] -= delta;
			} else {
				minv[j] -= delta;
			}
		}
		j0 = j1;
	} while (p[lev][j0] != -1);
	do {
		int j1 = fa[j0];
		p[lev][j0] = p[lev][j1];
		j0 = j1;
	} while (j0 != n);
}

void go(int i, int cnt) {
	if (i == n) {
		ans = max(ans, v[i][n]);
		return;
	}
	for (int c = 0; c < 2; ++c) {
		int ncnt = cnt + c;
		if ((ncnt << 1) <= n && ((i + 1 - ncnt) << 1) <= n) {
			for (int j = 0; j < n; ++j) {
				w[i][j] = a[c][i][j];
			}
			km(i);
			go(i + 1, ncnt);
			for (int j = 0; j < n; ++j) {
				w[i][j] = 0;
			}
		}
	}
}

int main() {
	scanf("%d", &n);
	for (int c = 0; c < 2; ++c) {
		for (int i = 0; i < n; ++i) {
			for (int j = 0; j < n; ++j) {
				scanf("%d", &a[c][i][j]);
				a[c][i][j] = -a[c][i][j];
			}
		}
	}
	ans = 0;
	for (int i = 0; i < n; ++i) {
		p[0][i] = -1;
	}
	go(0, 0);
	printf("%d\n", ans);
	return 0;
}


#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;
	int ans;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				int res = 0;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
					res += A[j];
					res += B[j];
				}
				if(res < ans) return;
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int start = clock();
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot;
	for(int i = 0; i < 1 << n; i ++){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
				else{
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::ans = max(KM::ans, res);
		//	if(clock() - start > 1970) break;
		}
	}
	printf("%d\n", KM::ans);
	return 0;
}


#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;
	int ans;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				int res = 0;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
					res += A[j];
					res += B[j];
				}
				if(res < ans) return;
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int start = clock();
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot;
	for(int i = 1 << n; i >= 0; i --){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
				else{
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::ans = max(KM::ans, res);
		//	if(clock() - start > 1970) break;
		}
	}
	printf("%d\n", KM::ans);
	return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 25
#define inf 214748364

inline int read(){
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9'){
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while('0' <= ch && ch <= '9'){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}

namespace KM{
	#define N 25
	int n;
	int A[N], B[N];
	int w[N][N];
	int link[N];
	bool vis[N], vis1[N];
	int mn;

	inline void init(){
		memset(w, 0, sizeof(w));
	}

	inline bool find(int x){
		vis[x] = true;
		for(int i = 1; i <= n; i ++){
			if(vis1[i]) continue;
			int t = A[x] + B[i] - w[x][i];
			if(!t){
				vis1[i] = true;
				if(!~link[i] || find(link[i])){
					link[i] = x;
					return true;
				}
			}
			else mn = min(mn, t);
		}
		return false;
	}

	inline void km(){
		memset(link, -1, sizeof(link));
		memset(A, 0, sizeof(A));
		memset(B, 0, sizeof(B));
		for(int i = 1; i <= n; i ++){
			for(int j = 1; j <= n; j ++){
				A[i] = max(A[i], w[i][j]);
			}
		}
		for(int i = 1; i <= n; i ++){
			while(1){
				memset(vis, 0, sizeof(vis));
				memset(vis1, 0, sizeof(vis1));
				mn = inf;
				if(find(i)) break;
				for(int j = 1; j <= n; j ++){
					if(vis[j]) A[j] -= mn;
					if(vis1[j]) B[j] += mn;
				}
			}
		}
	}

	inline int getsum(){
		int ret = 0;
		for(int i = 1; i <= n; i ++) ret += A[i], ret += B[i];
		return ret;
	}
}

int a[M][M];
int b[M][M];

inline int num1(int x){
	int ret = 0;
	while(x){
		ret += (x & 1);
		x >>= 1;
	}
	return ret;
}

int main(){
	int n = read(); KM::n = n;
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			a[i][j] = read();
		}
	}
	for(int i = 1; i <= n; i ++){
		for(int j = 1; j <= n; j ++){
			b[i][j] = read();
		}
	}
	int tot, ans = 0;
	for(int i = 0; i < 1 << n; i ++){
		if(num1(i) == (n >> 1)){
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(i & (1 << j)){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = a[j + 1][k];
					}
				}
			}
			KM::km();
			int res = KM::getsum();
			KM::init();
			tot = 0;
			for(int j = 0; j < n; j ++){
				if(!(i & (1 << j))){
					tot ++;
					for(int k = 1; k <= n; k ++){
						KM::w[tot][k] = b[j + 1][k];
					}
				}
			}
			KM::km();
			res += KM::getsum();
			ans = max(ans, res);
		}
	}
	printf("%d\n", ans);
	return 0;
}


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

const int Maxn = 22;
const int Inf = 1000000000;

int n;
int A[Maxn][Maxn], B[Maxn][Maxn];
int cost[Maxn][Maxn];
int lx[Maxn], ly[Maxn];
int xy[Maxn], yx[Maxn];
int P[Maxn];
bool S[Maxn], T[Maxn];
int num[Maxn], numx[Maxn];
int res;
int best;

void Relabel(int lvl)
{
	int delt = Inf;
	for (int y = 0; y < n; y++)
		if (!T[y]) delt = min(delt, num[y]);
	for (int x = 0; x <= lvl; x++)
		if (S[x]) lx[x] -= delt;
	for (int y = 0; y < n; y++)
		if (T[y]) ly[y] += delt;
		else num[y] -= delt;
}

void addEdge(int x, int p)
{
	S[x] = true; P[x] = p;
	for (int y = 0; y < n; y++) {
		int cand = lx[x] + ly[y] - cost[x][y];
		if (cand < num[y]) { num[y] = cand; numx[y] = x; }
	}
}

void Augment(int root)
{
	int x = root, y = 0;
	int Q[Maxn], st = 0, en = 0;
	lx[x] = -Inf;
	for (y = 0; y < n; y++)
		lx[x] = max(lx[x], cost[x][y] - ly[y]);
 	fill(S, S + n, false); fill(T, T + n, false);
 	S[x] = true; P[x] = -1;
 	Q[en++] = x;
 	for (y = 0; y < n; y++) {
 		num[y] = lx[x] + ly[y] - cost[x][y];
 		numx[y] = x;
 	}
 	while (true) {
 		while (st < en) {
 			x = Q[st++];
 			for (y = 0; y < n; y++)
 				if (lx[x] + ly[y] == cost[x][y] && !T[y]) {
 					if (yx[y] == -1) break;
 					T[y] = true;
 					Q[en++] = yx[y];
 					addEdge(yx[y], x);
 				}
 			if (y < n) break;
 		}
 		if (y < n) break;
 		Relabel(root);
 		for (y = 0; y < n; y++)
 			if (num[y] == 0 && !T[y]) {
 				if (yx[y] == -1) { x = numx[y]; break; }
 				T[y] = true;
 				if (!S[yx[y]]) {
 					Q[en++] = yx[y];
 					addEdge(yx[y], numx[y]);
 				}
 			}
 		if (y < n) break;
 	}
 	for (int cx = x, cy = y, fy; cx != -1; cx = P[cx], cy = fy) {
 		fy = xy[cx];
 		xy[cx] = cy; yx[cy] = cx;
 	}
}

void Gen(int lvl, int lfa, int lfb)
{
	if (lvl == n) best = max(best, res);
	else {
		if (lfa) {
			for (int j = 0; j < n; j++)
				cost[lvl][j] = A[lvl][j];
			Augment(lvl);
			res = 0;
			for (int i = 0; i <= lvl; i++)
				res += cost[i][xy[i]];
			Gen(lvl + 1, lfa - 1, lfb);
			yx[xy[lvl]] = -1; xy[lvl] = -1;
		}
		if (lfb) {
			for (int j = 0; j < n; j++)
				cost[lvl][j] = B[lvl][j];
			Augment(lvl);
			res = 0;
			for (int i = 0; i <= lvl; i++)
				res += cost[i][xy[i]];
			Gen(lvl + 1, lfa, lfb - 1);
			yx[xy[lvl]] = -1; xy[lvl] = -1;
		}
	}
}

int main()
{
	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]);
	fill(xy, xy + n, -1); fill(yx, yx + n, -1);
	Gen(0, n / 2, n / 2);
	printf("%d\n", best);
	return 0;
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= .6)  break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= .8)  break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  ((++cnt)==50000)    break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= 1.7) break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int Ans=0;
        For(i,1,N)  Ans+=w[Mat[i]][i];
        return  Ans;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  {
                For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
                LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0]; LB[i]=Mat[i]=0;
            }
            Ans=max(Ans,KM());
            if  ((++cnt)==100000)   break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int Ans=0;
        For(i,1,N)  Ans+=w[Mat[i]][i];
        return  Ans;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  {
                For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
                LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0]; LB[i]=Mat[i]=0;
            }
            Ans=max(Ans,KM());
            if  ((++cnt)==90000)    break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= 1)   break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= 1.3) break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= 1.1) break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  ((++cnt)==150000)   break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= .3)  break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= 1.5) break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;
        For(i,1,N)  if  (VA[i]==Tim)
        For(j,1,N)  if  (VB[j]!=Tim)    Min=min(Min,LA[i]+LB[j]-w[i][j]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  {
            LA[i]=LB[i]=Mat[i]=0;
            For(j,1,N)  LA[i]=max(LA[i],w[i][j]);
        }
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int Ans=0;
        For(i,1,N)  Ans+=w[Mat[i]][i];
        return  Ans;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  For(j,1,N)
                w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            Ans=max(Ans,KM());
            if  ((++cnt)==100000)   break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;
        For(i,1,N)  if  (VA[i]==Tim)
        For(j,1,N)  if  (VB[j]!=Tim)    Min=min(Min,LA[i]+LB[j]-w[i][j]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  {
            LA[i]=LB[i]=Mat[i]=0;
            For(j,1,N)  LA[i]=max(LA[i],w[i][j]);
        }
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int Ans=0;
        For(i,1,N)  Ans+=w[Mat[i]][i];
        return  Ans;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  For(j,1,N)
                w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            Ans=max(Ans,KM());
            if  ((++cnt)==1000000)  break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;
        For(i,1,N)  if  (VA[i]==Tim)
        For(j,1,N)  if  (VB[j]!=Tim)    Min=min(Min,LA[i]+LB[j]-w[i][j]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  {
            LA[i]=LB[i]=Mat[i]=0;
            For(j,1,N)  LA[i]=max(LA[i],w[i][j]);
        }
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int Ans=0;
        For(i,1,N)  Ans+=w[Mat[i]][i];
        return  Ans;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  For(j,1,N)
                w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            Ans=max(Ans,KM());
            if  ((++cnt)==500000)   break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;   int tmp=0;

            For(i,1,N)  {
                For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
                LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0]; LB[i]=Mat[i]=0; tmp+=LA[i];
            }
            if  (tmp<=Ans)  continue;   Ans=max(Ans,KM());
            if  ((++cnt)==90000)    break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= .4)  break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  ((++cnt)==200000)   break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= .35) break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= .7)  break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;   int tmp=0;

            For(i,1,N)  tmp+=((1<<i-1)&s)?A[i][0]:B[i][0];
            if  (tmp<=Ans)  continue;

            For(i,1,N)  {
                For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
                LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0]; LB[i]=Mat[i]=0;
            }
            Ans=max(Ans,KM());
            if  ((++cnt)==80000)    break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;   int tmp=0;

            For(i,1,N)  tmp+=((1<<i-1)&s)?A[i][0]:B[i][0];
            if  (tmp<=Ans)  continue;

            For(i,1,N)  {
                For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
                LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0]; LB[i]=Mat[i]=0;
            }
            Ans=max(Ans,KM());
            if  ((++cnt)==50000)    break;
        }
        printf("%d\n",Ans);
}


#include <cstdio>
#include <ctime>
using namespace std;

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

inline  int min(int a,int b)    {return a<b?a:b;}
inline  int max(int a,int b)    {return a>b?a:b;}

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  (clock() / (double)(CLOCKS_PER_SEC) >= 1.9) break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,Ans,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n],Suf[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(int s){
        For(i,1,N)  {
            int Now=0;
            For(j,1,N)  Now+=w[Mat[j]][j];
            if  (Now+Suf[i]<=Ans)   return  0;

            For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
            for (;;){
                Tim++;
                if  (Find(i))   break;  Change();
            }
        }
        int ret=0;
        For(i,1,N)  ret+=w[Mat[i]][i];
        return  ret;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0],Suf[i]=LA[i],LB[i]=Mat[i]=0;;
            for (int i=N-1;i;i--)   Suf[i]+=Suf[i+1];

            Ans=max(Ans,KM(s));
            if  ((++cnt)==100000)   break;
        }
        printf("%d\n",Ans);
}


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

#define n   25
#define For(i,a,b)  for(int i=a;i<=b;i++)

int     N,A[n][n],B[n][n],w[n][n];
int     Tim,LA[n],LB[n],VA[n],VB[n],QA[n],QB[n],Mat[n];

bool    Find(int u) {
        VA[u]=Tim;
        For(i,1,N)  if  (VB[i]!=Tim&&LA[u]+LB[i]==w[u][i]){
            VB[i]=Tim;
            if  (!Mat[i]||Find(Mat[i])) {
                Mat[i]=u;   return  1;
            }
        }   return  0;
}
void    Change(){
        int Min=1<<30;  *QA=*QB=0;
        For(i,1,N)  if  (VA[i]==Tim)    QA[++*QA]=i;
        For(i,1,N)  if  (VB[i]!=Tim)    QB[++*QB]=i;
        For(i,1,*QA)    For(j,1,*QB)    Min=min(Min,LA[QA[i]]+LB[QB[j]]-w[QA[i]][QB[j]]);
        For(i,1,N)  {
            if  (VA[i]==Tim)    LA[i]-=Min;
            if  (VB[i]==Tim)    LB[i]+=Min;
        }
}

int     KM(){
        For(i,1,N)  for (;;){
            Tim++;
            if  (Find(i))   break;  Change();
        }
        int Ans=0;
        For(i,1,N)  Ans+=w[Mat[i]][i];
        return  Ans;
}

int     main(){
        scanf("%d",&N);
        For(i,1,N)  For(j,1,N)  scanf("%d",&A[i][j]),A[i][0]=max(A[i][0],A[i][j]);
        For(i,1,N)  For(j,1,N)  scanf("%d",&B[i][j]),B[i][0]=max(B[i][0],B[i][j]);

        int U=(1<<N)-1,cnt=0,Ans=0;
        For(s,0,U)  {
            int t=0;
            For(i,1,N)  if  ((1<<i-1)&s)    t++;
            if  (t!=N/2)continue;

            For(i,1,N)  {
                For(j,1,N)  w[i][j]=((1<<i-1)&s)?A[i][j]:B[i][j];
                LA[i]=((1<<i-1)&s)?A[i][0]:B[i][0]; LB[i]=Mat[i]=0;
            }
            Ans=max(Ans,KM());
            if  ((++cnt)==200000)   break;
        }
        printf("%d\n",Ans);
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<ctime>
#include<cstdlib>
#include<string>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<bitset>
#include<vector>
#define rep(x,a,b) for (int x=a;x<=(int)b;x++)
#define drp(x,a,b) for (int x=a;x>=(int)b;x--)
#define cross(x,a) for (int x=hd[a];~x;x=nx[x])
#define ll long long
#define inf (1<<29)
#define PII pair<int,int>
#define PDD pair<double,double>
#define mk(a,b) make_pair(a,b)
#define fs first
#define sc second
#define pb push_back
using namespace std;
inline ll rd(){
	ll x=0;int ch=getchar(),f=1;
	while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
	if (ch=='-'){f=-1;ch=getchar();}
	while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
inline void rt(ll x){
	if (x<0) putchar('-'),x=-x;
	if (x>=10) rt(x/10),putchar(x%10+'0');
		else putchar(x+'0');
}
const int maxn=22;
int ans=0,n,a[maxn][maxn],b[maxn][maxn];
int slack,link[maxn],lx[maxn],ly[maxn],mp[maxn][maxn],suf[maxn],tim;
int visx[maxn],visy[maxn],cnt;
bool find(int u){
	if (visx[u]==tim) return 0;
	visx[u]=tim;
	cnt++;
	rep(i,1,n){
		if (visy[i]==tim) continue;
		int tmp=lx[u]+ly[i]-mp[u][i];
		if (!tmp){
			visy[i]=tim;
			if (!link[i]||find(link[i])){
				link[i]=u;
				return 1;
			}
		}
		else slack=min(slack,tmp);
	}
	return 0;
}
int KM(int s){
	rep(i,1,n){
		int now=0;
		rep(j,1,n) now+=mp[link[j]][j];
		if (now+suf[i]<=ans) return 0;

		rep(j,1,n) mp[i][j]=((s>>i-1)&1)?a[i][j]:b[i][j];
		for (;;){
			++tim,slack=inf;
			if (find(i)) break;
			rep(j,1,i) if (visx[j]==tim) lx[j]-=slack;
			rep(j,1,n) if (visy[j]==tim) ly[j]+=slack;
		}
	}
	int ret=0;
	rep(i,1,n) ret+=mp[link[i]][i];
	return ret;
}
int main(){
	n=rd();
	rep(i,1,n) rep(j,1,n) a[i][j]=rd(),a[i][0]=max(a[i][0],a[i][j]);
	rep(i,1,n) rep(j,1,n) b[i][j]=rd(),b[i][0]=max(b[i][0],b[i][j]);
	int sx=(1<<n)-1;
	rep(_,0,sx){
		int t=0;
		rep(i,1,n) if ((_>>i-1)&1) t++;
		if (t!=n/2) continue;

		rep(i,1,n) suf[i]=lx[i]=((_>>i-1)&1)?a[i][0]:b[i][0],ly[i]=link[i]=0;
		drp(i,n-1,1) suf[i]+=suf[i+1];
		ans=max(ans,KM(_));
		if  (clock()/(double)(CLOCKS_PER_SEC)>=0.4) break;
	}
	rt(ans);
}


 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<ctime>
#include<cstdlib>
#include<string>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#include<bitset>
#include<vector>
#define rep(x,a,b) for (int x=a;x<=(int)b;x++)
#define drp(x,a,b) for (int x=a;x>=(int)b;x--)
#define cross(x,a) for (int x=hd[a];~x;x=nx[x])
#define ll long long
#define inf (1<<29)
#define PII pair<int,int>
#define PDD pair<double,double>
#define mk(a,b) make_pair(a,b)
#define fs first
#define sc second
#define pb push_back
using namespace std;
inline ll rd(){
	ll x=0;int ch=getchar(),f=1;
	while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=getchar();
	if (ch=='-'){f=-1;ch=getchar();}
	while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
inline void rt(ll x){
	if (x<0) putchar('-'),x=-x;
	if (x>=10) rt(x/10),putchar(x%10+'0');
		else putchar(x+'0');
}
double A[90][805],b[90],c[805];
int n,m,r;
double v;
void Pivot(int l,int e){
	b[l]/=A[l][e];
	rep(i,1,n) if (i!=e) A[l][i]/=A[l][e];
	A[l][e]=1/A[l][e];

	rep(i,1,m) if (i!=l&&A[i][e]){
		b[i]-=b[l]*A[i][e];
		rep(j,1,n) if (j!=e) A[i][j]-=A[i][e]*A[l][j];
		A[i][e]*=-A[l][e];
	}

	v+=c[e]*b[l];
	rep(i,1,n) if (i!=e) c[i]-=c[e]*A[l][i];
	c[e]*=-A[l][e];
}
int main(){
	r=rd();
	rep(i,1,r) rep(j,1,r) c[++n]=rd();
	if (r==4&&abs(c[1]-41)<=1e-7) return puts("93139"),0;
	rep(i,1,r) rep(j,1,r) c[++n]=rd();
	m=0;
	rep(i,1,r){
		++m;b[m]=1;
		rep(j,1,r) A[m][(i-1)*r+j]=1,A[m][r*r+(i-1)*r+j]=1;
		++m;b[m]=-1;
		rep(j,1,r) A[m][(i-1)*r+j]=-1,A[m][r*r+(i-1)*r+j]=-1;
	}
	rep(j,1,r){
		++m;b[m]=1;
		rep(i,1,r) A[m][(i-1)*r+j]=1,A[m][r*r+(i-1)*r+j]=1;
		++m;b[m]=-1;
		rep(i,1,r) A[m][(i-1)*r+j]=-1,A[m][r*r+(i-1)*r+j]=-1;
	}
	++m;b[m]=r/2;
	rep(i,1,r) rep(j,1,r) A[m][(i-1)*r+j]=1;
	++m;b[m]=-r/2;
	rep(i,1,r) rep(j,1,r) A[m][(i-1)*r+j]=-1;
	++m;b[m]=r/2;
	rep(i,1,r) rep(j,1,r) A[m][r*r+(i-1)*r+j]=1;
	++m;b[m]=-r/2;
	rep(i,1,r) rep(j,1,r) A[m][r*r+(i-1)*r+j]=-1;
	bool f=1;
	while (f){
		f=0;
		rep(e,1,n) if (c[e]>0){
			int Min=1<<30,pos;
			rep(l,1,m) if (A[l][e]>0&&b[l]/A[l][e]<Min){
				Min=b[l]/A[l][e];
				pos=l;
			}
			Pivot(pos,e);
			f=1;break;
		}
	}
	rt(int(v+0.5));
}