#include <bits/stdc++.h>
using namespace std;
int dx[] = {-1, 0, 0, 1};
int dy[] = {0, -1, 1, 0};
int n, m;
int a[101][101];
int S, T;
int el;
int ea[100001];
int eb[100001];
int ec[100001];
int ef[100001];
int ew[100001];
vector<int> g[7001];
inline void addEdge(int a, int b, int c, int w) {
  ea[el] = a;
  eb[el] = b;
  ec[el] = c;
  ef[el] = 0;
  ew[el] = w;
  ea[el ^ 1] = b;
  eb[el ^ 1] = a;
  ec[el ^ 1] = 0;
  ef[el ^ 1] = 0;
  ew[el ^ 1] = -w;
  g[a].push_back(el);
  g[b].push_back(el ^ 1);
  el += 2;
}
int d[7001];
int p[7001];
int ok[7001];
int inq[7001];
queue<int> q;
inline void addq(int v, int dist, int pr) {
  if (ok[v] && d[v] <= dist) return;
  if (!inq[v]) {
    q.push(v);
    inq[v] = 1;
  }
  d[v] = dist;
  p[v] = pr;
  ok[v] = 1;
}
inline bool canE() {
  memset(ok, 0, sizeof(ok));
  memset(inq, 0, sizeof(inq));
  addq(S, 0, -1);
  while (!q.empty()) {
    int v = q.front();
    q.pop();
    inq[v] = 0;
    int curd = d[v];
    for (int i = g[v].size() - 1; i >= 0; --i) {
      int inde = g[v][i];
      if (ec[inde] - ef[inde] > 0) addq(eb[inde], curd + ew[inde], inde);
    }
  }
  return ok[T];
}
inline int updateE() {
  for (int i = T, inde; i != S; i = ea[inde]) {
    inde = p[i];
    ++ef[inde];
    --ef[inde ^ 1];
  }
  return d[T];
}
inline int minCostMaxFlow() {
  int r = 0;
  while (canE()) r += updateE();
  return r;
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < m; ++j) scanf("%d", &a[i][j]);
  S = n * m;
  T = S + 1;
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < m; ++j) {
      int ind = i * m + j;
      if ((i + j) & 1) {
        addEdge(ind, T, 1, 0);
      } else {
        addEdge(S, ind, 1, 0);
        for (int k = 0; k < 4; ++k) {
          int sx = i + dx[k];
          int sy = j + dy[k];
          if (0 <= sx && sx < n && 0 <= sy && sy < m)
            addEdge(ind, sx * m + sy, 1, !(a[i][j] == a[sx][sy]));
        }
      }
    }
  printf("%d\n", minCostMaxFlow());
  return 0;
}
