#include <bits/stdc++.h>
using namespace std;
template <class T>
void PV(T a, T b) {
  for (T i = a; i < b; ++i) cout << *i << " ";
  cout << endl;
}
template <class T>
void chmin(T &t, T f) {
  if (t > f) t = f;
}
template <class T>
void chmax(T &t, T f) {
  if (t < f) t = f;
}
const int MAXE = 200010;
const int MAXV = 10010;
const int INF = 0x3f3f3f3f;
struct MCMF {
  class Edge {
   public:
    int u, v, cap, cost, flow;
    Edge() {}
    Edge(int u, int v, int cap, int cost) {
      this->u = u;
      this->v = v;
      this->cap = cap;
      this->cost = cost;
      this->flow = 0;
    }
  };
  int V, E, Source, Sink;
  vector<vector<int> > G;
  Edge Edges[MAXE];
  int Father[MAXV], Dist[MAXV];
  bool InQ[MAXV];
  queue<int> Q;
  MCMF(int nVertex = 0, int source = 0, int sink = 0) {
    init(nVertex, source, sink);
  }
  void init(int nVertex, int source, int sink) {
    V = nVertex;
    Source = source;
    Sink = sink;
    E = 0;
    G = vector<vector<int> >(V, vector<int>());
  }
  bool SPFA(int start, int end) {
    Q = queue<int>();
    for (int x = 0; x < V; ++x) {
      Father[x] = -1;
      Dist[x] = INF;
      InQ[x] = false;
    }
    Q.push(start);
    Dist[start] = 0;
    InQ[start] = true;
    while (!Q.empty()) {
      int x = Q.front();
      Q.pop();
      InQ[x] = false;
      if (x == end) continue;
      for (size_t i = 0; i < G[x].size(); i++) {
        int e = G[x][i];
        int y = Edges[e].v;
        if (Edges[e].flow < Edges[e].cap && Dist[x] + Edges[e].cost < Dist[y]) {
          Father[y] = e;
          Dist[y] = Dist[x] + Edges[e].cost;
          if (!InQ[y]) {
            Q.push(y);
            InQ[y] = true;
          }
        }
      }
    }
    return (Father[end] != -1);
  }
  int MinCostMaxFlow(int &maxFlow, int &flowCost) {
    maxFlow = flowCost = 0;
    while (SPFA(Source, Sink)) {
      int flow = INF;
      for (int x = Sink; x != Source; x = Edges[Father[x]].u)
        flow = min(flow, Edges[Father[x]].cap - Edges[Father[x]].flow);
      for (int x = Sink; x != Source; x = Edges[Father[x]].u) {
        Edges[Father[x]].flow += flow;
        Edges[Father[x] ^ 1].flow -= flow;
      }
      maxFlow += flow;
      flowCost += flow * Dist[Sink];
    }
    return flowCost;
  }
  inline void addEdge(int u, int v, int cap, int cost) {
    Edges[E] = Edge(u, v, cap, cost);
    G[u].push_back(E++);
    Edges[E] = Edge(v, u, 0, -cost);
    G[v].push_back(E++);
  }
} mm;
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
int n, m;
int a[110][110];
int place(int x, int y) { return (x - 1) * m + y; }
int main() {
  ios_base::sync_with_stdio(0);
  cin >> n >> m;
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= m; ++j) cin >> a[i][j];
  int S = n * m + 1;
  int T = S + 1;
  MCMF g(T + 1, S, T);
  for (int i = 1; i <= n; ++i)
    for (int j = 1; j <= m; ++j)
      if ((i + j) & 1) {
        g.addEdge(S, place(i, j), 1, 0);
        for (int k = 0; k < 4; ++k) {
          int x = i + dx[k], y = j + dy[k];
          if (x >= 1 && x <= n && y >= 1 && y <= m)
            g.addEdge(place(i, j), place(x, y), 1, a[i][j] != a[x][y]);
        }
      } else {
        g.addEdge(place(i, j), T, 1, 0);
      }
  int flow, cost;
  g.MinCostMaxFlow(flow, cost);
  cout << cost << endl;
  return 0;
}
