#include <bits/stdc++.h>
using namespace std;
const int MAX = 81;
int shoes[MAX][MAX];
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
const int oo = 1 << 20;
struct MFMC {
  struct edge {
    int u, v, next;
    int flow, cap;
    int cost;
  };
  struct node {
    int u;
    int cost;
    node(int u = 0, int cost = 0) : u(u), cost(cost) {}
    bool operator<(const node &o) const { return cost > o.cost; }
  };
  int N, cnt;
  vector<edge> edges;
  vector<int> dist;
  vector<int> ant;
  vector<int> phi;
  vector<int> mark;
  MFMC(int N) : N(N) {
    edges.clear();
    ant = vector<int>(N, -1);
    dist = vector<int>(N);
    phi = vector<int>(N, 0);
    mark = vector<int>(N, -1);
    cnt = 0;
  }
  int add_node() { return cnt++; }
  void add(int u, int v, int cap, int cost) {
    edges.push_back((edge){u, v, ant[u], 0, cap, cost});
    ant[u] = (int)edges.size() - 1;
    edges.push_back((edge){v, u, ant[v], 0, 0, -cost});
    ant[v] = (int)edges.size() - 1;
  }
  void mfmc(int sr, int sk, int &flow, int &cost) {
    flow = 0;
    cost = 0;
    int u;
    for (int i = 0; i < N; ++i) phi[i] = 0;
    for (;;) {
      for (int i = 0; i < N; ++i) dist[i] = oo, mark[i] = -1;
      dist[sr] = 0;
      priority_queue<node> Q;
      Q.push(node(sr, 0));
      int c;
      while (!Q.empty()) {
        u = Q.top().u, c = Q.top().cost, Q.pop();
        if (dist[u] < c) continue;
        for (int i = ant[u]; i > -1; i = edges[i].next) {
          edge to = edges[i];
          int w = to.cost + phi[u] - phi[to.v];
          int rest = to.cap - to.flow;
          if (rest > 0 && w + dist[u] < dist[to.v]) {
            dist[to.v] = w + dist[u];
            Q.push(node(to.v, dist[to.v]));
            mark[to.v] = i;
          }
        }
      }
      if (mark[sk] == -1) break;
      int f = oo;
      int total = 0;
      for (u = sk; u != sr; u = edges[mark[u]].u) {
        f = min(f, edges[mark[u]].cap - edges[mark[u]].flow);
        total += edges[mark[u]].cost;
      }
      for (u = sk; u != sr; u = edges[mark[u]].u) {
        edges[mark[u]].flow += f;
        edges[1 ^ mark[u]].flow -= f;
      }
      flow += f;
      cost += total * f;
      for (int i = 0; i < N; ++i)
        if (mark[i] != -1) phi[i] += dist[i];
    }
  }
};
int N, M;
inline bool ok(int x, int n) { return x < n && x >= 0; }
inline int node(int i, int j) { return i * M + j; }
int main() {
  int i, j;
  scanf("%d%d", &N, &M);
  for (i = 0; i < N; ++i)
    for (j = 0; j < M; ++j) scanf("%d", &shoes[i][j]);
  MFMC net(N * M + 5);
  int src = N * M, sink = N * M + 1;
  for (i = 0; i < N; ++i)
    for (j = 0; j < M; ++j) {
      if ((i + j) & 1)
        net.add(node(i, j), sink, 1, 0);
      else
        net.add(src, node(i, j), 1, 0);
      if (((i + j) & 1)) continue;
      for (int k = 0; k < 4; ++k) {
        int tx = i + dx[k], ty = j + dy[k];
        if (ok(tx, N) && ok(ty, M)) {
          int w = (shoes[tx][ty] != shoes[i][j]);
          net.add(node(i, j), node(tx, ty), 1, w);
        }
      }
    }
  int flow, cost;
  net.mfmc(src, sink, flow, cost);
  cout << cost << endl;
  return 0;
}
