#include <bits/stdc++.h>
using namespace std;
const long long inf = 1e9 + 7;
const long long INF = 1LL << 60;
const long long mod = 1e9 + 7;
const long double eps = 1e-8;
const long double pi = acos(-1.0);
template <class T>
inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class FLOWTYPE>
struct Edge {
  long long rev, from, to;
  FLOWTYPE cap, icap;
  Edge(long long r, long long f, long long t, FLOWTYPE c)
      : rev(r), from(f), to(t), cap(c), icap(c) {}
  friend ostream &operator<<(ostream &s, const Edge &E) {
    if (E.cap > 0)
      return s << E.from << "->" << E.to << '(' << E.cap << ')';
    else
      return s;
  }
};
template <class FLOWTYPE>
struct Graph {
  vector<vector<Edge<FLOWTYPE>>> list;
  Graph(long long n = 0) : list(n) {}
  void init(long long n = 0) {
    list.clear();
    list.resize(n);
  }
  void reset() {
    for (long long i = 0; i < (long long)list.size(); ++i)
      for (long long j = 0; j < list[i].size(); ++j)
        list[i][j].cap = list[i][j].icap;
  }
  inline vector<Edge<FLOWTYPE>> &operator[](long long i) { return list[i]; }
  inline const size_t size() const { return list.size(); }
  inline Edge<FLOWTYPE> &redge(Edge<FLOWTYPE> e) {
    if (e.from != e.to)
      return list[e.to][e.rev];
    else
      return list[e.to][e.rev + 1];
  }
  void addedge(long long from, long long to, FLOWTYPE cap) {
    list[from].push_back(
        Edge<FLOWTYPE>((long long)list[to].size(), from, to, cap));
    list[to].push_back(
        Edge<FLOWTYPE>((long long)list[from].size() - 1, to, from, 0));
  }
  void add_undirected_edge(long long from, long long to, FLOWTYPE cap) {
    list[from].push_back(
        Edge<FLOWTYPE>((long long)list[to].size(), from, to, cap));
    list[to].push_back(
        Edge<FLOWTYPE>((long long)list[from].size() - 1, to, from, cap));
  }
};
template <class FLOWTYPE>
struct Dinic {
  const FLOWTYPE INF = 1 << 30;
  vector<long long> level, iter;
  Dinic() {}
  void dibfs(Graph<FLOWTYPE> &G, long long s) {
    level.assign((long long)G.size(), -1);
    level[s] = 0;
    queue<long long> que;
    que.push(s);
    while (!que.empty()) {
      long long v = que.front();
      que.pop();
      for (long long i = 0; i < G[v].size(); ++i) {
        Edge<FLOWTYPE> &e = G[v][i];
        if (level[e.to] < 0 && e.cap > 0) {
          level[e.to] = level[v] + 1;
          que.push(e.to);
        }
      }
    }
  }
  FLOWTYPE didfs(Graph<FLOWTYPE> &G, long long v, long long t, FLOWTYPE f) {
    if (v == t) return f;
    for (long long &i = iter[v]; i < G[v].size(); ++i) {
      Edge<FLOWTYPE> &e = G[v][i], &re = G.redge(e);
      if (level[v] < level[e.to] && e.cap > 0) {
        FLOWTYPE d = didfs(G, e.to, t, min(f, e.cap));
        if (d > 0) {
          e.cap -= d;
          re.cap += d;
          return d;
        }
      }
    }
    return 0;
  }
  FLOWTYPE solve(Graph<FLOWTYPE> &G, long long s, long long t) {
    level.assign((long long)G.size(), -1);
    iter.assign((long long)G.size(), 0);
    FLOWTYPE res = 0;
    while (true) {
      dibfs(G, s);
      if (level[t] < 0) return res;
      for (long long i = 0; i < (long long)iter.size(); ++i) iter[i] = 0;
      FLOWTYPE flow = 0;
      while ((flow = didfs(G, s, t, INF)) > 0) {
        res += flow;
      }
    }
  }
};
const long long dx[4] = {-1, 0, 1, 0};
const long long dy[4] = {0, 1, 0, -1};
void solve() {
  long long n, m;
  cin >> n >> m;
  vector<vector<char>> s(n, vector<char>(m));
  vector<bool> used(2 * n * m, false);
  long long cnt = 0;
  for (long long i = 0; i < n; i++) {
    for (long long j = 0; j < m; j++) {
      cin >> s[i][j];
      if (s[i][j] == '#') ++cnt;
    }
  }
  Graph<long long> g(2 * n * m + 2);
  long long sr = 2 * n * m, t = 2 * n * m + 1;
  long long co = 0;
  for (long long i = 0; i < n; i++) {
    for (long long j = 0; j < m; j++) {
      for (long long k = 0; k < 2; k++) {
        long long ni = i + dx[k], nj = j + dy[k];
        if (0 <= ni and ni < n and 0 <= nj and nj < m) {
          if (s[i][j] == '#' and s[ni][nj] == '#') {
            if (k == 0)
              g.addedge(sr, k * n * m + i * m + j, 1);
            else
              g.addedge(k * n * m + i * m + j, t, 1);
            ++co;
          }
        }
      }
    }
  }
  map<pair<long long, pair<long long, long long>>, long long> mp;
  for (long long i = 0; i < n; i++) {
    for (long long j = 0; j < m; j++) {
      for (long long k = 0; k < 2; k++) {
        long long ni = i + dx[k], nj = j + dy[k];
        mp[{k, {i, j}}] = k * n * m + i * m + j;
      }
      for (long long k = 2; k < 4; ++k) {
        long long ni = i + dx[k], nj = j + dy[k];
        long long nk = k - 2;
        mp[{k, {i, j}}] = nk * n * m + ni * m + nj;
      }
    }
  }
  for (long long i = 0; i < n; i++) {
    for (long long j = 0; j < m; j++) {
      for (long long k = 0; k < 4; k++) {
        long long ni = i + dx[k], nj = j + dy[k];
        long long nii = i + dx[(k + 1) % 4], njj = j + dy[(k + 1) % 4];
        if (0 <= ni and ni < n and 0 <= nj and nj < m and 0 <= nii and
            nii < n and 0 <= njj and njj < m) {
          if (s[i][j] == '#' and s[ni][nj] == '#' and s[nii][njj] == '#') {
            long long a = mp[{k, {i, j}}], b = mp[{(k + 1) % 4, {i, j}}];
            if (k % 2 == 1) swap(a, b);
            g.addedge(a, b, 1);
          }
        }
      }
    }
  }
  Dinic<long long> dic;
  long long flow = dic.solve(g, sr, t);
  cout << cnt - (co - flow) << endl;
}
signed main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  solve();
  return 0;
}
