#include <bits/stdc++.h>
using namespace std;
template <typename T>
void debug(T v, string delimiter = "\n") {
  for (__typeof(v.begin()) it = v.begin(), it_end = v.end(); it != it_end; it++)
    cout << *it << delimiter;
  cout << flush;
}
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};
string ds = "SENW";
const double PI = 4.0 * atan(1.0);
const long long WEIGHT_INF = 1LL << 60;
struct edge_t {
  int src, dest;
  long long capacity, cost, flow;
  edge_t* rev;
  edge_t(int src = -1, int dest = -1, long long capacity = 0,
         long long cost = 0, long long flow = 0)
      : src(src),
        dest(dest),
        capacity(capacity),
        cost(cost),
        flow(flow),
        rev(NULL) {}
  long long residue() const { return capacity - flow; }
};
class PrimalDual {
  vector<edge_t*>* graph;
  vector<edge_t*> edge_list;
  int n;
  struct data_t {
    int pos;
    long long cost;
    data_t(int pos, long long cost) : pos(pos), cost(cost) {}
    friend bool operator<(const data_t& d1, const data_t& d2) {
      return d1.cost > d2.cost;
    }
  };

 public:
  PrimalDual(int n) : n(n) { graph = new vector<edge_t*>[n]; }
  ~PrimalDual() {
    for (vector<edge_t*>::iterator it = edge_list.begin(),
                                   it_end = edge_list.end();
         it != it_end; ++it)
      delete *it;
    delete[] graph;
  }
  void add_edge(int src, int dest, long long capacity, long long cost) {
    edge_t* e = new edge_t(src, dest, capacity, cost);
    edge_list.push_back(e);
    graph[src].push_back(e);
  }
  void clear_flow() {
    for (vector<edge_t*>::iterator it = edge_list.begin(),
                                   it_end = edge_list.end();
         it != it_end; ++it)
      (*it)->flow = 0;
  }
  long long all_cost, all_flow;
  long long run(int s, int t, long long F) {
    all_cost = 0;
    all_flow = 0;
    clear_flow();
    while (all_flow < F) {
      vector<long long> dist(n, WEIGHT_INF);
      vector<edge_t*> log(n);
      queue<int> qu;
      qu.push(s);
      vector<int> inQueue(n);
      dist[s] = 0;
      inQueue[s] = 1;
      while (!qu.empty()) {
        int now = qu.front();
        qu.pop();
        inQueue[now] = 0;
        for (vector<edge_t*>::iterator it = graph[now].begin(),
                                       it_end = graph[now].end();
             it != it_end; ++it) {
          edge_t* e = *it;
          if (e->residue() <= 0) continue;
          if (dist[e->dest] > dist[now] + e->cost) {
            dist[e->dest] = dist[now] + e->cost;
            log[e->dest] = e;
            if (!inQueue[e->dest]) {
              inQueue[e->dest] = 1;
              qu.push(e->dest);
            }
          }
        }
      }
      if (log[t] == NULL) break;
      long long tau = F - all_flow;
      for (edge_t* u = log[t]; u; u = log[u->src]) tau = min(tau, u->residue());
      for (edge_t* u = log[t]; u; u = log[u->src]) {
        if (u->rev == NULL) {
          edge_t* rev_edge = new edge_t(u->dest, u->src, 0, -u->cost);
          u->rev = rev_edge;
          rev_edge->rev = u;
          graph[u->dest].push_back(rev_edge);
          edge_list.push_back(rev_edge);
        }
        all_cost += u->cost * tau;
        u->flow += tau;
        u->rev->flow -= tau;
      }
      all_flow += tau;
    }
    return all_cost;
  }
};
int a[100][100];
int main() {
  int r, c;
  cin >> r >> c;
  for (int i = 0, i_end = (int(r)); i < i_end; i++)
    for (int j = 0, j_end = (int(c)); j < j_end; j++) cin >> a[i][j];
  int source = r * c, sink = source + 1;
  PrimalDual D(r * c + 2);
  for (int i = 0, i_end = (int(r)); i < i_end; i++)
    for (int j = 0, j_end = (int(c)); j < j_end; j++)
      if ((i + j) % 2 == 0) {
        for (int k = 0, k_end = (int(4)); k < k_end; k++) {
          int nr = i + dy[k];
          int nc = j + dx[k];
          if (((0) <= (nr) && (nr) < (r)) && ((0) <= (nc) && (nc) < (c))) {
            D.add_edge(i * c + j, nr * c + nc, 1, a[i][j] != a[nr][nc] ? 1 : 0);
          }
        }
      }
  for (int i = 0, i_end = (int(r)); i < i_end; i++)
    for (int j = 0, j_end = (int(c)); j < j_end; j++) {
      if ((i + j) % 2 == 0) {
        D.add_edge(source, i * c + j, 1, 0);
      } else {
        D.add_edge(i * c + j, sink, 1, 0);
      }
    }
  cout << D.run(source, sink, 1 << 28) << endl;
  return 0;
}
