#pragma GCC optimize("O3")
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
#include <bitset>
using namespace std;

using ll = long long;
using P = pair<int, ll>;
using T = tuple<ll, int, int>;

template <class T> inline T chmax(T &a, const T b) {return a = (a < b) ? b : a;}
template <class T> inline T chmin(T &a, const T b) {return a = (a > b) ? b : a;}

constexpr int MOD = 1e9 + 7;
constexpr int inf = 1e9;
constexpr long long INF = 1e18;

#define all(a) (a).begin(), (a).end()

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};

vector<ll> dijkstra(int s, vector<vector<pair<int, ll>>> &G){
    int n = G.size();
    vector<ll> dist(n, INF);
    dist[s] = 0;
    priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> que;
    que.emplace(0, s);

    while(que.size()){
        ll ccost; int cv; tie(ccost, cv) = que.top(); que.pop();
        if(dist[cv] < ccost) continue;

        for(auto nxt : G[cv]){
            int nv; ll ncost; tie(nv, ncost) = nxt;
            if(ccost + ncost < dist[nv]){
                dist[nv] = ccost + ncost;
                que.emplace(dist[nv], nv);
            }
        }
    }

    return dist;
}

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    int r, c; cin>>r>>c;
    vector<vector<int>> a(r, vector<int>(c - 1));
    for(int i=0; i<r; i++){
        for(int j=0; j<c-1; j++) cin>>a[i][j];
    }
    vector<vector<int>> b(r - 1, vector<int>(c));
    for(int i=0; i<r-1; i++){
        for(int j=0; j<c; j++) cin>>b[i][j];
    }

    int sz = 2 * r * c;
    vector<vector<P>> G(sz);
    for(int i=0; i<r; i++){
        for(int j=0; j<c; j++){
            if(j + 1 < c) G[i * c + j].emplace_back(i * c + j + 1, a[i][j]);
            if(0 <= j - 1) G[i * c + j].emplace_back(i * c + j - 1, a[i][j - 1]);
            if(i + 1 < r) G[i * c + j].emplace_back((i + 1) * c + j, b[i][j]);
            
            // (r, c) -> (r - i, c) の移動で i + 1 のコストがかかることを以下で実現
            // 2 階に上がるのにコストが 1 かかる
            G[i * c + j].emplace_back(r * c + i * c + j, 1);
            // 1 階に下がるのにはコストがかからない
            G[r * c + i * c + j].emplace_back(i * c + j, 0);
            // 2 階で 1 つ下のマスに行くのにコストが 1 かかる
            if(0 <= i - 1) G[r * c + i * c + j].emplace_back(r * c + (i - 1) * c + j, 1);
        }
    }

    auto dist = dijkstra(0, G);

    cout << dist[r * c - 1] << endl;

    return 0;
}
#include <bits/stdc++.h>

#include <random>
#include <unordered_map>
#include <unordered_set>
using namespace std;
#pragma GCC target("avx2")
#pragma GCC optimize("O3,unroll-loops")
using ll = long long;
using ull = unsigned long long;
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define _overload3(_1, _2, _3, name, ...) name
#define _rep(i, n) for (int(i) = 0; (i) < int(n); (i)++)
#define repi(i, a, b) for (int(i) = (a); (i) < int(b); (i)++)
#define rep(...) _overload3(__VA_ARGS__, repi, _rep)(__VA_ARGS__)
template <class T>
bool chmax(T& a, const T& b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T>
bool chmin(T& a, const T& b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}
constexpr int dy[4] = {-1, 0, 1, 0};
constexpr int dx[4] = {0, -1, 0, 1};
constexpr ll MOD = 1'000'000'007LL; /*998'244'353LL;*/

template <typename T>
struct Dijkstra {
    vector<vector<pair<int, short>>> e;
    vector<T> cost;
    Dijkstra(int V) : e(V) {}
    void add(int u, int v, T weight) {
        e[u].push_back({v, weight});
        e[v].push_back({u, weight});
    }
    void add_directed(int from, int to, T weight) {
        e[from].push_back({to, weight});
    }
    vector<T>& calculate(int s, T def) {
        cost.resize(e.size(), def);
        priority_queue<pair<T, int>> pq;
        cost[s] = 0;
        pq.push({0, s});
        while (!pq.empty()) {
            int n = pq.top().second;
            if (-pq.top().first != cost[n]) {
                pq.pop();
                continue;
            }
            pq.pop();
            for (int i = 0; i < e[n].size(); i++) {
                if (cost[e[n][i].first] > cost[n] + e[n][i].second) {
                    cost[e[n][i].first] = cost[n] + e[n][i].second;
                    pq.push({-cost[e[n][i].first], e[n][i].first});
                }
            }
        }
        return cost;
    }
};

int R, C;
Dijkstra<int> G(0);

signed main() {
    cin >> R >> C;
    G = Dijkstra<int>(2 * R * C);
    rep(i, R) {
        rep(j, C - 1) {
            int a;
            cin >> a;
            G.add(i * C + j, i * C + j + 1, a);
        }
    }
    rep(i, R - 1) {
        rep(j, C) {
            int a;
            cin >> a;
            G.add_directed(i * C + j, (i + 1) * C + j, a);
        }
    }
    rep(i, R) {
        rep(j, C) {
            G.add_directed(i * C + j, R * C + i * C + j, 1);
            G.add_directed(R * C + i * C + j, i * C + j, 0);
            if (i - 1 >= 0)
                G.add_directed(R * C + i * C + j, R * C + (i - 1) * C + j, 1);
        }
    }
    cout << G.calculate(0, 2e9)[R * C - 1] << endl;
}