#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;   }