// #pragma once
#include <bits/stdc++.h>
using i64 = int_fast64_t;
using namespace std;
#define repeat(i, a, b) for(int i = (a); (i) < (b); ++(i))
#define rep(i, n) repeat(i, 0, n)

int popcnt(uint32_t x) { return __builtin_popcount(x); }
int popcnt(uint64_t x) { return __builtin_popcountll(x); }
// bit が1になっている一番上（左）の位
int bsr(uint32_t x) { return 31 - __builtin_clz(x); }
int bsr(uint64_t x) { return 63 - __builtin_clzll(x); }
// bit が1になっている一番下（右）の位
int bsf(uint32_t x) { return __builtin_ctz(x); }
int bsf(uint64_t x) { return __builtin_ctzll(x); }

struct bit_vector {
    static constexpr size_t B = 64;
    size_t n;
    ::std::vector<uint64_t> d;
    explicit bit_vector(size_t _n = 0) : n(_n), d((n + B - 1) / B) {}
    void erase_last() {
        if(n % B) d.back() &= uint64_t(-1) >> (B - n % B);
    }
    size_t size() const { return n; }
    bool operator[](size_t i) const { return (d[i / B] >> (i % B) & 1) != 0; }
    void set(size_t i, bool f = true) {
        if(f)
            d[i / B] |= 1ULL << (i % B);
        else
            d[i / B] &= ~(1ULL << (i % B));
    }
    void reset() { fill(d.begin(), d.end(), 0); }
    void reset(size_t i) { set(i, false); }
    void push_back(bool f) {
        if(n % B == 0) d.push_back(0);
        set(n, f);
        n++;
    }
    bool empty() const {
        for(auto& x : d)
            if(x) return false;
        return true;
    }

    size_t bsf() const {
        auto m = d.size();
        for(size_t i = 0; i < m; i++) {
            if(d[i]) return i * B + ::bsf(d[i]);
        }
        assert(false);
    }

    size_t count() const {
        size_t sm = 0;
        for(auto x : d) sm += popcnt(x);
        return sm;
    }

    void swap_elms(size_t a, size_t b) {
        bool f = (*this)[a];
        set(a, (*this)[b]);
        set(b, f);
    }

    template <class OP>
    bit_vector& op1(OP op) {
        for(auto& x : d) x = op(x);
        return *this;
    }

    template <class OP>
    bit_vector& op2(const bit_vector& r, OP op) {
        assert(n == r.n);
        for(size_t i = 0; i < d.size(); i++) d[i] = op(d[i], r.d[i]);
        return *this;
    }

    bit_vector& flip() {
        op1(::std::bit_not<uint64_t>());
        if(n % B) d.back() &= ~(-1ULL << (n % B));
        return *this;
    }
    bit_vector& operator&=(const bit_vector& r) { return op2(r, ::std::bit_and<uint64_t>()); }
    bit_vector& operator|=(const bit_vector& r) { return op2(r, ::std::bit_or<uint64_t>()); }
    bit_vector& operator^=(const bit_vector& r) { return op2(r, ::std::bit_xor<uint64_t>()); }
    bit_vector& operator<<=(const size_t& s) {
        auto block = s / B, rem = s % B;
        if(d.size() <= block) {
            reset();
            return *this;
        }
        for(size_t i = d.size() - 1; i > block; i--) {
            if(rem == 0)
                d[i] = d[i - block];
            else
                d[i] = d[i - block] << rem | d[i - block - 1] >> (B - rem);
        }
        d[block] = d[0] << rem;
        erase_last();
        fill(d.begin(), d.begin() + block, 0ULL);
        return *this;
    }
    bit_vector& operator>>=(const size_t& s) {
        auto block = s / B, rem = s % B;
        if(d.size() <= block) {
            reset();
            return *this;
        }
        for(size_t i = 0; i < d.size() - block - 1; i++) {
            if(rem == 0)
                d[i] = d[i + block];
            else
                d[i] = d[i + block + 1] << (B - rem) | d[i + block] >> rem;
        }
        d[d.size() - block - 1] = d.back() >> rem;
        fill(d.begin() + d.size() - block, d.end(), 0ULL);
        return *this;
    }
    bit_vector& operator~() const { return bit_vector(*this).flip(); }
    bit_vector operator&(const bit_vector& r) const { return bit_vector(*this) &= r; }
    bit_vector operator|(const bit_vector& r) const { return bit_vector(*this) |= r; }
    bit_vector operator^(const bit_vector& r) const { return bit_vector(*this) ^= r; }
    bit_vector operator<<(const size_t& s) const { return bit_vector(*this) <<= s; }
    bit_vector operator>>(const size_t& s) const { return bit_vector(*this) >>= s; }

    bit_vector substr(size_t st, size_t le) const {
        assert(st + le <= n);
        bit_vector res(le);
        size_t i = 0;
        while(i < le) {
            res.d[i / B] |= d[(st + i) / B] >> ((st + i) % B) << (i % B);
            i += ::std::min(B - i % B, B - (st + i) % B);
        }
        res.erase_last();
        return res;
    }
    bool substr_match(size_t st, const bit_vector& pat) const {
        size_t le = pat.size();
        assert(st + le <= n);
        size_t i = 0;
        while(i < le) {
            size_t u = ::std::min({le - i, B - i % B, B - (st + i) % B});
            uint64_t z = pat.d[i / B] >> (i % B) ^ d[(st + i) / B] >> ((st + i) % B);
            if(z << (B - u)) return false;
            i += u;
        }
        return true;
    }
    bool operator==(const bit_vector& r) const { return d == r.d; }
};

int main() {
    constexpr int MAX_V = 6400;
    int H, W;
    cin >> H >> W;
    vector<vector<int>> A(H, vector<int>(W)), B(H, vector<int>(W));
    rep(i, H) rep(j, W) cin >> A[i][j];
    rep(i, H) rep(j, W) cin >> B[i][j];
    vector<vector<int>> field(H, vector<int>(W));
    rep(i, H) {
        rep(j, W) {
            field[i][j] = abs(A[i][j] - B[i][j]);
        }
    }
    vector<vector<bit_vector>> dp(H, vector<bit_vector>(W, bit_vector(2 * MAX_V)));
    dp[0][0].set(field[0][0] + MAX_V);
    rep(i, H) {
        rep(j, W) {
            if(i - 1 >= 0) {
                dp[i][j] |= (dp[i - 1][j] << field[i][j]);
                dp[i][j] |= (dp[i - 1][j] >> field[i][j]);
            }
            if(j - 1 >= 0) {
                dp[i][j] |= (dp[i][j - 1] << field[i][j]);
                dp[i][j] |= (dp[i][j - 1] >> field[i][j]);
            }
        }
    }
    rep(i, 12800) {
        if(dp[H - 1][W - 1][MAX_V + i] or dp[H - 1][W - 1][MAX_V - i]) {
            cout << i << endl;
            return 0;
        }
    }
}

Measured memory_bytes: 10752