#include <bits/stdc++.h>

using namespace std;

const int N = 505;

int n, m, a[N][N], b[N][N];

struct info { int x, y, p; };
queue <info> q;
bool inq[N][N][2];
int dis[N][N][2];
inline void spfa()
{
	memset(dis, 0x3f, sizeof(dis));
	
	dis[1][1][0] = 0; q.push( (info) { 1, 1, 0 } ); inq[1][1][0] = 1;
	
	int x, y, p;
	while (!q.empty())
	{
		x = q.front().x, y = q.front().y, p = q.front().p; q.pop(); inq[x][y][p] = 0;
	
		if (y < m)
		{
			if (dis[x][y][p] + a[x][y] < dis[x][y + 1][0])
			{
				dis[x][y + 1][0] = dis[x][y][p] + a[x][y];
				if (!inq[x][y + 1][0])
				{
					q.push( (info) { x, y + 1, 0 } );
					inq[x][y + 1][0] = 1;
				}
			}
		}
		if (y > 1)
		{
			if (dis[x][y][p] + a[x][y - 1] < dis[x][y - 1][0])
			{
				dis[x][y - 1][0] = dis[x][y][p] + a[x][y - 1];
				if (!inq[x][y - 1][0])
				{
					q.push( (info) { x, y - 1, 0 } );
					inq[x][y - 1][0] = 1;
				}
			}
		}
		if (x < n)
		{
			if (dis[x][y][p] + b[x][y] < dis[x + 1][y][0])
			{
				dis[x + 1][y][0] = dis[x][y][p] + b[x][y];
				if (!inq[x + 1][y][0])
				{
					q.push( (info) { x + 1, y, 0 } );
					inq[x + 1][y][0] = 1;
				}
			}
		}
		if (x == 1) continue;
		if (p == 0)
		{
			if (dis[x][y][p] + 2 < dis[x - 1][y][1])
			{
				dis[x - 1][y][1] = dis[x][y][p] + 2;
				if (!inq[x - 1][y][1])
				{
					q.push( (info) { x - 1, y, 1 } );
					inq[x - 1][y][1] = 1;
				}
			}
		}
		if (p == 1)
		{
			if (dis[x][y][p] + 1 < dis[x - 1][y][1])
			{
				dis[x - 1][y][1] = dis[x][y][p] + 1;
				if (!inq[x - 1][y][1])
				{
					q.push( (info) { x - 1, y, 1 } );
					inq[x - 1][y][1] = 1;
				}
			}
		}
	}
}

int main()
{
	scanf ("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
	for (int j = 1; j < m; j++)
	scanf ("%d", &a[i][j]);
	for (int i = 1; i < n; i++)
	for (int j = 1; j <= m; j++)
	scanf ("%d", &b[i][j]);
	
	spfa();
	printf ("%d\n", dis[n][m][0]);
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define V vector
#define pb push_back
#define eb emplace_back
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define rep(i, n) for (int i = 0; i < (n); i++)
#define all(v) v.begin(), v.end()
#define allr(v) v.rbegin(), v.rend()
#define sz(x) int(x.size())
#define pcnt __builtin_popcountll
template <typename T> bool chmin(T &a, const T &b) {if(a > b){a = b; return true;} return false;}
template <typename T> bool chmax(T &a, const T &b) {if(a < b){a = b; return true;} return false;}
template <typename T> void print(T a) {cout << a << ' ';}
template <typename T> void printe(T a) {cout << a << endl;}
template <typename T> void printv(T a) {rep(i, sz(a))print(a[i]); cout<<endl;}
template <typename T> void printp(pair<T, T> a) {print(a.first); cout<<a.second<<endl;}
template <typename A, size_t N, typename T> void Fill (A (&array)[N], const T & val) {fill ((T*)array, (T*)(array+N), val);}
template <typename T> using vc = vector<T>;
template <typename T> using vv = vc<vc<T>>;
template <typename T> using vvv = vc<vv<T>>;
using ll = long long;
using P = pair<int, int>;
using Pl = pair<ll, ll>;
using vi = vc<int>;
using vvi = vv<int>;
using vl = vc<ll>;
using vvl = vv<ll>;
vi di = {-1, 1,  0, 0, -1, -1,  1, 1};
vi dj = { 0, 0, -1, 1, -1,  1, -1, 1};

// 宣言は Dijkstra<コストの型> d(頂点数, コストの型の最大値);
template <class T>
struct Dijkstra {
    struct edge {int to; T cost;};
    vv<edge> g;
    vc<T> dist;
    Dijkstra (int n, T INF): g(n), dist(n, INF) {}

    // u -> vにコストwの辺を張る
    void add_edge (int u, int v, T w) {
        g[u].pb({v, w});
    }
    // startから各点への最小コストを返す
    vc<T> get (int start) {
        priority_queue<pair<T, T>, V<pair<T, T>>, greater<pair<T, T>>> que;
        dist[start] = 0;
        que.emplace(0, start);
        while (!que.empty()) {
            int c = que.top().first, v = que.top().second; que.pop();
            if (dist[v] != c) continue;
            for (auto e : g[v]) {
                if (chmin(dist[e.to], c + e.cost)) que.emplace(dist[e.to], e.to);
            }
        }
        return dist;
    }
};

int main () {
    int h, w; cin >> h >> w;
    Dijkstra<ll> d(h*w*2, 2e9);
    rep(i, h) rep(j, w-1) {
        int a; cin >> a;
        d.add_edge(i*w + j, i*w + j+1, a);
        d.add_edge(i*w + j+1, i*w + j, a);
    }
    rep(i, h-1) rep(j, w) {
        int b; cin >> b;
        d.add_edge(i*w + j, (i+1)*w + j, b);
    }
    rep(i, h) rep(j, w) {
        d.add_edge(i*w + j, h*w + i*w + j, 1); // 上の階に行く
        d.add_edge(h*w + i*w + j, i*w + j, 0); // 下の階に降りる
        if (i > 0) d.add_edge(h*w + i*w + j, h*w + (i-1)*w + j, 1); // 上の階で下に移動する
    }
    auto res = d.get(0);
    // int ans = min(res[h*w-1], res[2*h*w-1]);
    ll ans = res[h*w-1]; // 下に移動してゴールにつくことはないから, 2*h*w-1は考えなくていい
    cout << ans << endl;
    return 0;
}