// Original C++ solution (slower):
// #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 = 100000;

    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;

        }

    }

}

// Optimized solution to the same problem (faster):
// #pragma once

#include <bits/stdc++.h>

using i64 = int_fast64_t;

#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() {

    std::ios::sync_with_stdio(false);

    std::cin.tie(nullptr);

    

    constexpr int MAX_V = 6400;

    int H, W;

    std::cin >> H >> W;

    std::vector<std::vector<int>> A(H, std::vector<int>(W)), B(H, std::vector<int>(W));

    rep(i, H) rep(j, W) std::cin >> A[i][j];

    rep(i, H) rep(j, W) std::cin >> B[i][j];

    std::vector<std::vector<int>> field(H, std::vector<int>(W));

    rep(i, H) {

        rep(j, W) {

            field[i][j] = abs(A[i][j] - B[i][j]);

        }

    }

    std::vector<std::vector<bit_vector>> dp(H, std::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]) {

            std::cout << i << std::endl;

            return 0;

        }

    }

}

// Fastest known solution for this problem: