/* Stay hungry, stay foolish. */
#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<sstream>
#include<stack>
#include<ctime>
#include<cmath>
#include<cctype>
#include<climits>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<bitset>
#include<complex>
using namespace std;
/*
#define getchar() getc()
char buf[1<<15],*fs,*ft;
inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft)?0:*fs++;}
*/
template <class _T> inline void read(_T &_x) {
int _t; bool _flag=false;
while((_t=getchar())!=‘-‘&&(_t<‘0‘||_t>‘9‘)) ;
if(_t==‘-‘) _flag=true,_t=getchar(); _x=_t-‘0‘;
while((_t=getchar())>=‘0‘&&_t<=‘9‘) _x=_x*10+_t-‘0‘;
if(_flag) _x=-_x;
}
typedef long long LL;
const int maxn = 500;
const int maxm = 100000;
const double eps = 1e-7;
struct Edge {
int v, from, nxt, flow; double cost;
Edge() {}
Edge(int a, int b, int c, double d): v(a), nxt(b), flow(c), cost(d) {}
}e[maxm];
int fir[maxn], ecnt, pre[maxn], preu[maxn];
double dis[maxn]; bool vis[maxn];
inline void addedge(int a, int b, int c, double d) {
e[++ecnt] = Edge(b, fir[a], c, d), fir[a] = ecnt;
e[++ecnt] = Edge(a, fir[b], 0, -d), fir[b] = ecnt;
}
int n, sink, a[maxn][maxn], b[maxn][maxn];
inline bool spfa() {
memset(dis, 0xfe, sizeof (double) * (sink + 1));
memset(vis, false, sizeof (bool) * (sink + 1));
double DMIN = dis[0];
queue<int> q; dis[0] = 0, q.push(0);
while (!q.empty()) {
int now = q.front(); q.pop(); vis[now] = false;
for (int u = fir[now]; u; u = e[u].nxt) if (e[u].flow) {
if (dis[e[u].v] < dis[now] + e[u].cost) {
dis[e[u].v] = dis[now] + e[u].cost;
pre[e[u].v] = now, preu[e[u].v] = u;
if (!vis[e[u].v]) {
vis[e[u].v] = true;
q.push(e[u].v);
}
}
}
}
return dis[sink] != DMIN;
}
double augment() {
int now = sink;
while (now != 0) {
e[preu[now]].flow -= 1;
e[preu[now] ^ 1].flow += 1;
now = pre[now];
}
return dis[sink];
}
double mcmf() {
double ret = 0;
while (spfa()) {
ret += augment();
}
return ret;
}
double Run(double ans) {
ecnt = 1;
memset(fir, 0, sizeof (int) * (sink + 1));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
addedge(i, j + n, 1, a[i][j] - ans * b[i][j]);
}
}
for (int i = 1; i <= n; ++i) addedge(0, i, 1, 0);
for (int i = 1; i <= n; ++i) addedge(n + i, sink, 1, 0);
mcmf();
int ansa = 0, ansb = 0;
for (int i = 1; i <= n; ++i) {
for (int u = fir[i]; u; u = e[u].nxt) {
if (e[u].flow == 0 && e[u].v > n && e[u].v < sink) {
ansa += a[i][e[u].v - n], ansb += b[i][e[u].v - n];
}
}
}
return (double)ansa / ansb;
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
read(n); sink = n + n + 1;
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
read(a[i][j]);
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
read(b[i][j]);
double prev, ans = 0;
do {
prev = ans, ans = Run(ans);
} while (fabs(ans - prev) > eps);
printf("%.6lf", ans);
return 0;
}