#include <bits/stdc++.h>
#define re register int
using namespace std;
const int L = 5e3 + 10, N = 3e5 + 10, M = 6e5 + 10;
struct edge
{
int x, y, w;
}e[M];
int top, fa[N];
int n, m, a[L][L], id[N], cnt, ans;
bool flag[N];
bool cmp(edge i, edge j) { return i.w < j.w; }
int Count_id(int i, int j)
{
return (i - 1) * m + j;
}
int find(int x)
{
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
fa[find(x)] = find(y);
}
bool kruskal(int k)
{
for (re i = 1; i <= n * m; i ++) fa[i] = i, flag[i] = false;
for (re i = 1; i <= top; i ++)
{
int x = e[i].x, y = e[i].y, w = e[i].w;
if (find(x) != find(y) && w <= k)
{
merge(x, y);
flag[x] = true;
flag[y] = true;
}
}
for (re i = 1; i <= cnt; i ++)
if (!flag[id[i]]) return false;
return true;
}
int binary_search()
{
int l = 0, r = 1e9;
sort(e + 1, e + top + 1, cmp);
while (l <= r)
{
int mid = (l + r) >> 1;
if (kruskal(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> m;
for (re i = 1; i <= n; i ++)
for (re j = 1; j <= m; j ++)
{
cin >> a[i][j];
if (j == 1) continue;
e[++ top] = (edge){Count_id(i, j), Count_id(i, j - 1), abs(a[i][j] - a[i][j - 1])};
if (i == 1) continue;
e[++ top] = (edge){Count_id(i, j), Count_id(i - 1, j), abs(a[i][j] - a[i - 1][j])};
}
for (re i = 1; i <= n; i ++)
for (re j = 1; j <= m; j ++)
{
int x;
cin >> x;
if (x) id[++ cnt] = Count_id(i, j);
}
cout << binary_search();
return 0;
}