#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 80010
#define M 110
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m, s, t, ans;
int dd[M][M], head[N], add_edge, dis[N], now[N];
int u[] = {0, 0, 0, 1, -1}, v[] = {0, 1, -1, 0, 0};
struct node {
int next, to, val;
}edge[N];
int read() {
int s = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void add(int from, int to, int dis) {
edge[++add_edge].next = head[from];
edge[add_edge].to = to;
edge[add_edge].val = dis;
head[from] = add_edge;
}
void link() {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
int pb = (i - 1) * m + j;
if ((i + j) % 2 == 0) {
add(s, pb, dd[i][j]);
add(pb, s, 0);
for (int k = 1; k <= 4; k++) {
int x = i + u[k], y = j + v[k];
int pa = (x - 1) * m + y;
if (x >= 1 && x <= n && y >= 1 && y <= m) {
add(pb, pa, inf);
add(pa, pb, 0);
}
}
} else {
add(pb, t, dd[i][j]);
add(t, pb, 0);
}
}
}
int bfs() {
for (int i = s; i <= t; i++) dis[i] = inf;
queue<int> q; q.push(s), dis[s] = 1, now[s] = head[s];
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = head[x]; i; i = edge[i].next) {
int to = edge[i].to;
if (edge[i].val > 0 && dis[to] == inf) {
q.push(to);
now[to] = head[to];
dis[to] = dis[x] + 1;
if (to == t) return 1;
}
}
}
return 0;
}
int dfs(int x, int sum) {
if (x == t) return sum;
int k, res = 0;
for (int i = now[x]; i && sum; i = edge[i].next) {
now[x] = i;
int to = edge[i].to;
if (edge[i].val > 0 && (dis[to] == dis[x] + 1)) {
k = dfs(to, min(sum, edge[i].val));
if (!k) dis[to] = inf;
edge[i].val -= k;
edge[i ^ 1].val += k;
res += k, sum -= k;
}
}
return res;
}
int main() {
n = read(), m = read(), s = 0, t = n * m + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
dd[i][j] = read(), ans += dd[i][j];
link();
while (bfs())
ans -= dfs(s, inf);
cout << ans;
}