#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e15; // 这里初始化写成int，调了一个上午，惨痛教训
const int N = 80 + 5;
long long P[N][N], R[N][N], D[N][N], f[N][N][N][N];
int n;
long long dp[N][N][2];

int main(){
	freopen("travel.in", "r", stdin);
	freopen("travel.out", "w", stdout);
	scanf("%d", &n);
	for(int i = 1; i <= n ; i++)
		for(int j = 1; j <= n; j++)
			 scanf("%lld", &P[i][j]);
	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j < n; j++)
			scanf("%lld", &R[i][j]);
	
	for(int i = 1; i < n; i++)
		for(int j = 1; j <= n; j++)
			scanf("%lld", &D[i][j]);
	
	memset(f, 0x3f, sizeof(f));
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			f[i][j][i][j] = 0;
	//f[i][j][x][y]先预处理出(i,j)->(x,y)的最小代价			
	//((x,y)显然在(i,j)的右下角 
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			for(int x = i; x <= n; x++)
				for(int y = j; y <= n; y++){
					if(x == i && y == j){
						f[i][j][x][y] = 0;
						continue;
					}
					if(x != i) 
						f[i][j][x][y] = min(f[i][j][x][y], f[i][j][x - 1][y] + D[x - 1][y]);
					if(y != j)
						f[i][j][x][y] = min(f[i][j][x][y], f[i][j][x][y - 1] + R[x][y - 1]);
				}
		
	//dp[x][y][0]表示从(1,1)到(x,y)的最小次数 
	//dp[x][y][1]表示从(1,1)到(x,y)的余额	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			dp[i][j][0] = inf;	
	dp[1][1][0] = dp[1][1][1] = 0;
	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			for(int x = 1; x <= i; x++) // 寻找停留的点 
				for(int y = 1; y <= j; y++){
					long long cnt1 =  max(0ll, f[x][y][i][j] - dp[x][y][1] + P[x][y] - 1) / P[x][y]; // 需要取上整
					long long cnt2 = dp[x][y][0] + cnt1 + 1ll*(i - x + j - y);//(1,1)到(i,j)的次数 
					long long res = dp[x][y][1] + cnt1 * P[x][y] - f[x][y][i][j];//余额还剩res 
					if(cnt2 < dp[i][j][0] || (cnt2 == dp[i][j][0] && res > dp[i][j][1])){ //两种情况 
						dp[i][j][0] = cnt2;//选择次数少的，或者相同时，选择余额多的 
						dp[i][j][1] = res;
					}
				}
	
	printf("%lld\n", dp[n][n][0]);		
	return 0;
}
