#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
// Returns -1 for unmatched items.
// Complexity: O(V*E)
VI BipartiteMatch(const VVI &mat, VI *back_match = NULL) {
  int max_item = -1;
  VI fmat(mat.size(), -1), seen(mat.size(), -1), prev(mat.size());
  for (auto row : mat) if (row.size()) max_item = max(max_item, *max_element(row.begin(), row.end()));
  VI bmat(max_item+1, -1);

  for (int i = 0; i < mat.size(); i++) {
    VI q(1, i);
    seen[i] = i; prev[i] = -1;
    int x, y;
    while (!q.empty()) {
      x = q.back(); q.pop_back();
      for (auto it : mat[x]) {
        int bm = bmat[it];
        if (bm == -1) {y = it; goto found_match;}
        if (seen[bm] < i) {
          seen[bm] = i; prev[bm] = x;
          q.push_back(bm);
        }
      }
    }
    continue;
found_match:
    while (x != -1) {
      bmat[y] = x;
      swap(y, fmat[x]);
      x = prev[x];
    }
  }

  if (back_match) back_match->swap(bmat);
  return fmat;
}

int X, Y;
char G[101][101];
int comp[101][101], edge[10001];

bool doit(int x, int y, char ch, int c) {
  if (x < 0 || x >= X || y < 0 || y >= Y) return false;
  if (G[y][x] != ch || comp[y][x]) return true;
  comp[y][x] = c;
  if (!doit(x+1, y  , ch, c)) edge[c] = 1;
  if (!doit(x-1, y  , ch, c)) edge[c] = 1;
  if (!doit(x  , y+1, ch, c)) edge[c] = 1;
  if (!doit(x  , y-1, ch, c)) edge[c] = 1;
  return true;
}

int main() {
  while (cin >> Y >> X) {
    for (int y = 0; y < Y; y++) cin >> G[y];
    memset(comp, 0, sizeof(comp));
    memset(edge, 0, sizeof(edge));
    int ncomp = 0;
    for (int y = 0; y < Y; y++)
    for (int x = 0; x < X; x++) if (!comp[y][x]) {
      doit(x, y, G[y][x], ++ncomp);
    }
//for (int y = 0; y < Y; y++) {
//for (int x = 0; x < X; x++) cout << ' ' << comp[y][x];
//cout << endl;
//}

    VVI match(ncomp+1);
    for (int x = 0; x < X; x++)
    for (int y = 0; y < Y; y++) if (!edge[comp[y][x]])
    for (int x2 = x-1; x2 <= x+1; x2++) if (x2 >= 0 && x2 < X)
    for (int y2 = y-1; y2 <= y+1; y2++) if (y2 >= 0 && y2 < Y && abs(x2-x) + abs(y2-y) == 1) {
      if (edge[comp[y2][x2]] || comp[y][x] == comp[y2][x2]) continue;
      if (G[y][x] == '1') match[comp[y ][x ]].push_back(comp[y2][x2]);
      if (G[y][x] == '0') match[comp[y2][x2]].push_back(comp[y ][x ]);
    }

    int ret = 0;
    for (int c = 1; c <= ncomp; c++) {
      if (edge[c]) { ret++; continue; }
      VI& v = match[c];
      sort(v.begin(), v.end());
      v.erase(unique(v.begin(), v.end()), v.end());
    }
    VI v = BipartiteMatch(match);
    for (auto x : v) ret += (x != -1);
    cout << ret << endl;
  }
}
