#include <bits/stdc++.h>
using namespace std;
const int inf = 80 * 80 * 5;
struct Rib {
  int from, to;
  int c, f, w;
};
struct Vertex {
  int flow;
  bool used;
  int dist;
  int phi;
  vector<int> ribs;
  int how;
};
int w, h;
int a[85][85];
int s, t;
Rib r[80 * 80 * 4 + 10];
Vertex v[80 * 80 + 10];
void read() {
  cin >> h >> w;
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      cin >> a[i][j];
    }
  }
}
int rcnt = 0;
void add_rib(int from, int to, int cost, int capacity) {
  r[rcnt].c = capacity;
  r[rcnt].f = 0;
  r[rcnt].from = from;
  r[rcnt].to = to;
  r[rcnt].w = cost;
  v[from].ribs.push_back(rcnt);
  rcnt++;
}
void add_rib(int from, int to, int cost) {
  add_rib(from, to, cost, 1);
  add_rib(to, from, -cost, 0);
}
void prepare() {
  s = h * w;
  t = s + 1;
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      if ((i + j) % 2 == 0) {
        add_rib(s, i * w + j, 0);
        int dx[] = {0, 0, -1, 1};
        int dy[] = {-1, 1, 0, 0};
        for (int k = 0; k < 4; k++) {
          int ni = i + dx[k];
          int nj = j + dy[k];
          if (ni >= 0 && ni < h && nj >= 0 && nj < w) {
            add_rib(i * w + j, ni * w + nj, a[i][j] != a[ni][nj]);
          }
        }
      } else {
        add_rib(i * w + j, t, 0);
      }
    }
  }
}
void dejkstra() {
  struct GoInfo {
    int dist;
    int vert;
    int rib;
    bool operator<(const GoInfo &g) const {
      if (dist == g.dist) {
        if (vert == g.vert) {
          return rib < g.rib;
        }
        return vert < g.vert;
      }
      return dist < g.dist;
    }
    GoInfo(int _dist, int _vert, int _rib) {
      dist = _dist;
      vert = _vert;
      rib = _rib;
    }
  };
  for (int i = 0; i <= t; i++) {
    v[i].phi += v[i].dist;
    v[i].dist = inf;
    v[i].how = -1;
    v[i].used = false;
  }
  v[s].dist = 0;
  set<GoInfo> q;
  q.insert(GoInfo(0, s, -1));
  while (!q.empty()) {
    GoInfo cur = *q.begin();
    q.erase(q.begin());
    if (v[cur.vert].used) continue;
    v[cur.vert].used = true;
    v[cur.vert].dist = cur.dist;
    v[cur.vert].how = cur.rib;
    vector<int> &ribs = v[cur.vert].ribs;
    for (int i = 0; i < ribs.size(); i++) {
      Rib &rib = r[ribs[i]];
      if (rib.c > rib.f) {
        q.insert(
            GoInfo(v[rib.from].dist + rib.w + (v[rib.from].phi - v[rib.to].phi),
                   rib.to, ribs[i]));
      }
    }
  }
}
int min_cost_max_flow() {
  int total_cost = 0;
  while (true) {
    dejkstra();
    if (v[t].how == -1) break;
    int cur = t;
    total_cost += v[t].dist + (v[t].phi - v[s].phi);
    do {
      r[v[cur].how].f++;
      r[v[cur].how ^ 1].f--;
      cur = r[v[cur].how].from;
    } while (cur != s);
  }
  return total_cost;
}
int main() {
  read();
  prepare();
  cout << min_cost_max_flow();
  return 0;
}
