#include <bits/stdc++.h>   #pragma warning(disable : 4996)   using namespace std;   long long __gcd(long long a, long long b) {     while (a != 0) {       long long __t = b % a;       b = a;       a = __t;     }     return b;   }   class Graph {    public:     struct edge;       private:     unsigned N;     vector<long long> pot;     vector<vector<edge*> > a;     bool Dijkstra(unsigned from, unsigned to, vector<edge*>& pr) {       fill(pr.begin(), pr.end(), nullptr);       vector<long long> d(N, (long long)1e18);       d[from] = 0;       priority_queue<pair<long long, unsigned>,                      vector<pair<long long, unsigned> >,                      greater<pair<long long, unsigned> > >           q;       q.push({0, from});       while (!q.empty()) {         long long cost = q.top().first;         unsigned v = q.top().second;         q.pop();         if (cost > d[v]) continue;         for (auto& e : a[v]) {           if (e->capLeftFrom(v)) {             unsigned u = e->from(v);             if (d[u] > d[v] + e->costFrom(v) + pot[v] - pot[u]) {               d[u] = d[v] + e->costFrom(v) + pot[v] - pot[u];               pr[u] = e;               q.push({d[u], u});             }           }         }       }       if (d[to] == (long long)1e18) return false;       for (unsigned i = 0; i < N; i++)         pot[i] += (d[i] != (long long)1e18 ? d[i] : d[to]);       return true;     }       public:     struct edge {       unsigned v1, v2;       long long c1, c2;       long long f1, f2;       long long cost1, cost2;       edge(unsigned v1, unsigned v2, long long c1, long long c2, long long cost1,            long long cost2)           : v1(v1),             v2(v2),             c1(c1),             c2(c2),             f1(0),             f2(0),             cost1(cost1),             cost2(cost2) {}       inline unsigned& from(unsigned v) { return (v == v1 ? v2 : v1); }       inline long long& capFrom(unsigned v) { return (v == v1 ? c1 : c2); }       inline long long& capTo(unsigned v) { return (v == v1 ? c2 : c1); }       inline long long& flowFrom(unsigned v) { return (v == v1 ? f1 : f2); }       inline long long& flowTo(unsigned v) { return (v == v1 ? f2 : f1); }       inline long long capLeftFrom(unsigned v) const {         return (v == v1 ? c1 - f1 : c2 - f2);       }       inline long long capLeftTo(unsigned v) const {         return (v == v1 ? c2 - f2 : c1 - f1);       }       inline long long& costFrom(unsigned v) { return (v == v1 ? cost1 : cost2); }       inline long long& costTo(unsigned v) { return (v == v1 ? cost2 : cost1); }     };     Graph() : N(0), a(N) {}     Graph(unsigned N) : N(N), a(N), pot(N) {}     inline void addEdge(unsigned v1, unsigned v2, long long cap1, long long cap2,                         long long cost1, long long cost2) {       edge* ne = new edge(v1, v2, cap1, cap2, cost1, cost2);       a[v1].push_back(ne);       a[v2].push_back(ne);     }     pair<int, int> maxFlowMinCost(unsigned from, unsigned to) {       fill(pot.begin(), pot.end(), (long long)1e18);       pot[from] = 0;       for (unsigned i = 0; i < N; i++)         for (unsigned j = 0; j < N; j++)           if (pot[j] < (int)1e9)             for (auto& e : a[j])               if (j == e->v1 && pot[e->v2] > pot[j] + e->cost1)                 pot[e->v2] = pot[j] + e->cost1;       long long resFlow = 0, resCost = 0;       vector<edge*> pr(N, nullptr);       while (Dijkstra(from, to, pr)) {         long long newFlow = (int)1e9, newCost = 0;         unsigned v = to;         while (v != from) {           newFlow = min(newFlow, pr[v]->capLeftTo(v));           newCost += pr[v]->costTo(v);           v = pr[v]->from(v);         }         v = to;         while (v != from) {           pr[v]->flowTo(v) += newFlow;           pr[v]->flowFrom(v) -= newFlow;           v = pr[v]->from(v);         }         resFlow += newFlow;         resCost += newFlow * newCost;       }       return {resFlow, resCost};     }   };   unsigned N, M;   int dx[] = {-1, 0, 1, 0};   int dy[] = {0, 1, 0, -1};   inline bool correctCord(int x, int y) {     return (x >= 0 && x < N && y >= 0 && y < M);   }   inline unsigned getNum(unsigned x, unsigned y) { return 2 + x * M + y; }   int main() {     cin.tie();     cout.tie();     cerr.tie();     ios_base::sync_with_stdio(false);     cin >> N >> M;     vector<vector<int> > a(N, vector<int>(M));     for (unsigned i = 0; i < N; i++)       for (unsigned j = 0; j < M; j++) cin >> a[i][j];     Graph g(2 + N * M);     for (int i = 0; i < N; i++) {       for (int j = 0; j < M; j++) {         if ((i + j) % 2)           g.addEdge(0, getNum(i, j), 1, 0, 0, 0);         else           g.addEdge(getNum(i, j), 1, 1, 0, 0, 0);         if ((i + j) % 2) {           for (int d = 0; d < 4; d++) {             int nx = i + dx[d], ny = j + dy[d];             if (correctCord(nx, ny))               g.addEdge(getNum(i, j), getNum(nx, ny), 1, 0, a[i][j] != a[nx][ny],                         -(a[i][j] != a[nx][ny]));           }         }       }     }     cout << g.maxFlowMinCost(0, 1).second << endl;     return 0;   }