#include <bits/stdc++.h>
using namespace std;
struct edge {
  int flow;
  int next;
  int inv;
  int cap;
  int cost;
};
const int N = 1100000;
vector<edge> v[N];
int d[N];
int phi[N];
int from[N];
bool vis[N];
void add_edge(int x1, int x2, int x3, int x4) {
  edge x;
  x.next = x2;
  x.cost = x4;
  x.cap = x3;
  x.flow = 0;
  x.inv = v[x2].size();
  v[x1].push_back(x);
  x.next = x1;
  x.cost = -x4;
  x.cap = 0;
  x.flow = 0;
  x.inv = v[x1].size() - 1;
  v[x2].push_back(x);
}
const int inf = (int)1e9;
void init() {
  for (int i = 0; i < N; i++) {
    phi[i] = 0;
    v[i].clear();
  }
}
void bfs(int n) {
  for (int i = 0; i < n; i++) vis[i] = false;
  queue<int> q;
  q.push(0);
  vis[0] = true;
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    for (int i = 0; i < v[x].size(); i++)
      if (!vis[v[x][i].next] && v[x][i].cap > v[x][i].flow) {
        vis[v[x][i].next] = true;
        from[v[x][i].next] = v[x][i].inv;
        q.push(v[x][i].next);
      }
  }
}
void dijkstra(int n) {
  for (int i = 0; i < n; i++) {
    d[i] = inf;
    vis[i] = false;
  }
  for (int i = 0; i < n; i++) vis[i] = false;
  set<pair<int, int> > q;
  d[0] = 0;
  for (int i = 1; i < n; i++) {
    d[i] = inf;
    q.insert(make_pair(d[i], i));
  }
  q.insert(make_pair(0, 0));
  while (!q.empty()) {
    int x = q.begin()->second;
    vis[x] = true;
    q.erase(q.begin());
    if (d[x] == inf) break;
    for (int i = 0; i < v[x].size(); i++)
      if (!vis[v[x][i].next] && v[x][i].cap > v[x][i].flow) {
        int to = v[x][i].next;
        if (d[to] > d[x] + v[x][i].cost + phi[x] - phi[to]) {
          q.erase(make_pair(d[to], to));
          d[to] = d[x] + v[x][i].cost + phi[x] - phi[to];
          from[to] = v[x][i].inv;
          q.insert(make_pair(d[to], to));
        }
      }
  }
}
int id[N];
void fuckin_levit(int n) {
  for (int i = 0; i < n; i++) {
    d[i] = inf;
    id[i] = 0;
  }
  d[0] = 0;
  deque<int> q;
  q.push_back(0);
  while (!q.empty()) {
    int x = q.front();
    q.pop_front();
    vis[x] = true;
    if (d[x] == inf) break;
    id[x] = 1;
    for (int i = 0; i < v[x].size(); i++)
      if (v[x][i].cap - v[x][i].flow > 0) {
        int to = v[x][i].next;
        int len = v[x][i].cost;
        if (d[to] > d[x] + len) {
          d[to] = d[x] + len;
          if (id[to] == 0)
            q.push_front(to);
          else if (id[to] == 1)
            q.push_back(to);
          from[to] = v[x][i].inv;
          id[to] = 1;
        }
      }
  }
}
pair<int, int> maxflow(int n, int mode) {
  int res_flow = 0;
  int res_cost = 0;
  while (true) {
    if (mode == 1) dijkstra(n);
    if (mode == 0) bfs(n);
    if (mode == 2) fuckin_levit(n);
    if (!vis[n - 1]) break;
    if (d[n - 1] == inf) break;
    if (mode == 1) {
      for (int i = 0; i < n - 1; i++) phi[i] += vis[i] ? d[i] : d[n - 1];
    }
    int x = n - 1;
    int dflow = inf;
    int dcost = 0;
    while (x != 0) {
      int a = v[x][from[x]].next;
      int b = v[x][from[x]].inv;
      dflow = min(dflow, v[a][b].cap - v[a][b].flow);
      dcost += v[a][b].cost;
      x = a;
    }
    x = n - 1;
    while (x != 0) {
      int a = v[x][from[x]].next;
      int b = v[x][from[x]].inv;
      v[a][b].flow += dflow;
      v[x][from[x]].flow -= dflow;
      x = a;
    }
    res_flow += dflow;
    res_cost += dflow * dcost;
  }
  return make_pair(res_flow, res_cost);
}
int a[100][100];
vector<pair<int, int> > v1;
vector<pair<int, int> > v2;
int main() {
  cin.sync_with_stdio(false);
  cin.tie(0);
  int n, m;
  cin >> n >> m;
  init();
  for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++) {
      cin >> a[i][j];
      if (((i + j) % 2) == 0)
        v1.push_back(make_pair(i, j));
      else
        v2.push_back(make_pair(i, j));
    }
  for (int i = 0; i < v2.size(); i++)
    add_edge(i + v1.size() + 1, n * m + 1, 1, 0);
  for (int i = 0; i < n * m / 2; i++) add_edge(0, i + 1, 1, 0);
  for (int i = 0; i < v1.size(); i++)
    for (int j = 0; j < v2.size(); j++) {
      int cost = 1;
      if (a[v1[i].first][v1[i].second] == a[v2[j].first][v2[j].second])
        cost = 0;
      if ((abs(v1[i].first - v2[j].first) + abs(v1[i].second - v2[j].second)) ==
          1)
        if (cost == 0) add_edge(i + 1, j + v1.size() + 1, 1, cost);
    }
  maxflow(n * m + 2, 0);
  for (int i = 0; i < v1.size(); i++)
    for (int j = 0; j < v2.size(); j++) {
      int cost = 1;
      if (a[v1[i].first][v1[i].second] == a[v2[j].first][v2[j].second])
        cost = 0;
      if ((abs(v1[i].first - v2[j].first) + abs(v1[i].second - v2[j].second)) ==
          1)
        if (cost == 1) add_edge(i + 1, j + v1.size() + 1, 1, cost);
    }
  pair<int, int> res = maxflow(n * m + 2, 2);
  cout << res.second << "\n";
  return 0;
}
