#include <bits/stdc++.h>
using namespace std;
using LL = long long;
struct MinCostMaxFlow {
  struct Edge {
    int to, c, f, cost;
    Edge(int to, int c, int f, int cost) : to(to), c(c), f(f), cost(cost) {}
  };
  int n, source, sink;
  MinCostMaxFlow(int n, int source, int sink)
      : n(n), source(source), sink(sink) {}
  static const int MAXN = 80 * 80 + 10;
  static const int INF = 1e9;
  vector<int> G[MAXN];
  vector<Edge> edge;
  void addEdge(int u, int v, int c, int cost) {
    G[u].push_back(edge.size());
    edge.push_back(Edge(v, c, 0, cost));
    G[v].push_back(edge.size());
    edge.push_back(Edge(u, 0, 0, -cost));
  }
  int dis[MAXN], nxt[MAXN];
  bool inqueue[MAXN];
  int maxFlow() {
    int res = 0;
    while (1) {
      for (int i = 0; i <= n; ++i) dis[i] = INF, inqueue[i] = 0;
      queue<int> qu;
      qu.push(source);
      dis[source] = 0, inqueue[source] = 1;
      while (qu.size()) {
        int u = qu.front();
        qu.pop(), inqueue[u] = 0;
        for (int id : G[u]) {
          int v = edge[id].to;
          if (dis[v] > dis[u] + edge[id].cost && edge[id].c > edge[id].f) {
            dis[v] = dis[u] + edge[id].cost, nxt[v] = id ^ 1;
            if (!inqueue[v]) {
              qu.push(v), inqueue[v] = 1;
            }
          }
        }
      }
      if (dis[sink] == INF) return res;
      int cur = sink, val = INF;
      while (cur != source) {
        int id = nxt[cur];
        cur = edge[id].to;
        val = min(val, edge[id ^ 1].c - edge[id ^ 1].f);
      }
      cur = sink, res += val * dis[sink];
      while (cur != source) {
        int id = nxt[cur];
        cur = edge[id].to;
        edge[id].f -= val, edge[id ^ 1].f += val;
      }
    }
  }
};
int n, m;
vector<int> dx{-1, 0, 1, 0}, dy{0, 1, 0, -1};
vector<vector<int> > a;
int to1D(int x, int y) { return x * m + y; }
bool valid(int x, int y) { return x >= 0 && x < n && y >= 0 && y < m; }
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> m;
  a.assign(n, vector<int>(m));
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) cin >> a[i][j];
  }
  MinCostMaxFlow mcmf(n * m + 2, n * m, n * m + 1);
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      int u = to1D(i, j);
      if ((i + j) & 1)
        mcmf.addEdge(mcmf.source, u, 1, 0);
      else
        mcmf.addEdge(u, mcmf.sink, 1, 0);
      if ((i + j) & 1) {
        for (int dir = 0; dir < 4; ++dir) {
          int x = i + dx[dir], y = j + dy[dir];
          if (!valid(x, y)) continue;
          int v = to1D(x, y);
          mcmf.addEdge(u, v, 1, a[i][j] != a[x][y]);
        }
      }
    }
  }
  cout << mcmf.maxFlow() << '\n';
  return 0;
}
