#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PII = pair<ll, ll>;
#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
template<typename T> void chmin(T &a, const T &b) { a = min(a, b); }
template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }
struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;
#ifdef DEBUG_ 
#include "../program_contest_library/memo/dump.hpp"
#else
#define dump(...)
#endif
const ll INF = 1LL<<60;

template<class T>
struct dinic {
    struct edge{
        int to;
        T cap;
        int rev;
        bool isrev;
    };

    vector<vector<edge>> G;
    vector<int> level, iter;

    void bfs(int s) {
        level.assign(G.size(), -1);
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while(que.size()) {
            int v = que.front(); que.pop();
            for(auto i: G[v]) {
                if(i.cap > 0 && level[i.to] < 0) {
                    level[i.to] = level[v] + 1;
                    que.push(i.to);
                }
            }
        }
    }

    T dfs(int v, const int t, T f) {
        if(v == t) return f;
        for(int &i = iter[v]; i<(ll)G[v].size(); ++i) {
            edge &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to]) {
                T d = dfs(e.to, t, min(f, e.cap));
                if(d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    dinic() {}
    dinic(int n) : G(n), level(n), iter(n) {}

    void add_edge(int from, int to, T cap) {
        G[from].push_back({to, cap, (int)G[to].size(), false});
        G[to].push_back({from, 0, (int)G[from].size()-1, true});
    }

    // sからtへ流量fを流す
    T maxflow(int s, int t, T f = 1LL<<30) {
        T flow = 0;
        while(1) {
            bfs(s);
            if(level[t] < 0) return flow;
            iter.assign(G.size(), 0);
            T tmp;
            while((tmp = dfs(s, t, f)) > 0) flow += tmp;
        }
    }

    // sからtへ1流す
    T flow(int s, int t) {
        bfs(s);
        if(level[t] < 0) return 0;
        iter.assign(G.size(), 0);
        return dfs(s, t, 1);
    }
    // 始点，終点tのフローで辺e=(from,to)の容量を1増やしたときの最大流の変化
    // 並列辺はたぶんバグる
    T add(int from, int to, int s, int t) {
        for(auto &e: G[from]) {
            if(e.to == to && !e.isrev) {
                e.cap++;
                break;
            }
        }
        return flow(s, t);
    }
    // 始点s，終点tのフローで辺e=(from,to)の容量を1減らしたときの最大流の変化
    // 並列辺はたぶんバグる
    T sub(int from, int to, int s, int t) {
        for(auto &e: G[from]) {
            if(e.to == to && !e.isrev) {
                T diff = 0;
                // 辺(from,to)で容量いっぱいに流れている
                if(e.cap == 0) {
                    // 残余グラフでfrom→toのパスがない
                    if(flow(from, to) == 0) {
                        flow(t, to);
                        flow(from, s);
                        diff = -1;
                    }
                    G[e.to][e.rev].cap--;
                } else {
                    e.cap--;
                }
                return diff;
            }
        }
        assert(false); // 存在しない辺を減らそうとした
    }

    friend ostream &operator <<(ostream& out, const dinic& a){
        out << endl;
        for(int i = 0; i < (int)a.G.size(); i++) {
            for(auto &e : a.G[i]) {
                if(e.isrev) continue;
                auto &rev_e = a.G[e.to][e.rev];
                out << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
            }
        }
        return out;
    }
};

int main(void) {
    ll h, w;
    cin >> h >> w;
    vector<string> v(h);
    REP(i, h) cin >> v[i];

    dinic<ll> graph(h*w+h*(w-1)+(h-1)*w+2);
    ll s = h*w+h*(w-1)+(h-1)*w, t = s+1;
    ll num = h*w, ret = 0;

    REP(i, h) REP(j, w) {
        if(v[i][j] == '#') {
            graph.add_edge(s, i*w+j, 1);
            graph.add_edge(i*w+j, t, 1);
        } else {
            graph.add_edge(s, i*w+j, 0);
            graph.add_edge(i*w+j, t, 0);
        }
    }
    REP(i, h) {
        REP(j, w-1) {
            // (i,j)と(i,j+1)が両方横 → 1得る
            if(v[i][j]=='.' || v[i][j+1]=='.') continue;
            ret++;
            graph.add_edge(s, num, 1);
            graph.add_edge(num, i*w+j, INF);
            graph.add_edge(num, i*w+j+1, INF);
            num++;
        }
    }
    REP(j, w) {
        REP(i, h-1) {
            // (i,j)と(i+1,j)が両方縦 → 1得る
            if(v[i][j]=='.' || v[i+1][j]=='.') continue;
            ret++;
            graph.add_edge(num, t, 1);
            graph.add_edge(i*w+j, num, INF);
            graph.add_edge((i+1)*w+j, num, INF);
            num++;
        }
    }

    cout << graph.maxflow(s, t) - ret << endl;
    // dump(graph);

    return 0;
}

### Prompt

Create a solution in cpp for the following problem:

problem

Given the squares of $ R * C $. Each square is either an empty square or a square with a hole. The given square meets the following conditions.

* The cells with holes are connected. (You can move a square with a hole in the cross direction to any square with a hole)
* Empty cells are connected.



You can generate rectangular tiles of any length with a width of $ 1 $. I would like to install multiple tiles to fill all the holes in the square. When installing tiles, the following restrictions must be observed.

* Tiles can only be installed vertically or horizontally in the $ 2 $ direction.
* Do not install more than one tile on one square.
* There should be no tiles on the squares without holes.



Please answer the minimum number of tiles when all the squares with holes are filled with tiles while observing the above restrictions.



output

Output the minimum number of times. Please also output a line break at the end.

Example

Input

5 5
.....
.#.#.
.###.
.#.#.
.....


Output

3

### Response

```cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using PII = pair<ll, ll>;
#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
template<typename T> void chmin(T &a, const T &b) { a = min(a, b); }
template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }
struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;
#ifdef DEBUG_ 
#include "../program_contest_library/memo/dump.hpp"
#else
#define dump(...)
#endif
const ll INF = 1LL<<60;

template<class T>
struct dinic {
    struct edge{
        int to;
        T cap;
        int rev;
        bool isrev;
    };

    vector<vector<edge>> G;
    vector<int> level, iter;

    void bfs(int s) {
        level.assign(G.size(), -1);
        queue<int> que;
        level[s] = 0;
        que.push(s);
        while(que.size()) {
            int v = que.front(); que.pop();
            for(auto i: G[v]) {
                if(i.cap > 0 && level[i.to] < 0) {
                    level[i.to] = level[v] + 1;
                    que.push(i.to);
                }
            }
        }
    }

    T dfs(int v, const int t, T f) {
        if(v == t) return f;
        for(int &i = iter[v]; i<(ll)G[v].size(); ++i) {
            edge &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to]) {
                T d = dfs(e.to, t, min(f, e.cap));
                if(d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }

    dinic() {}
    dinic(int n) : G(n), level(n), iter(n) {}

    void add_edge(int from, int to, T cap) {
        G[from].push_back({to, cap, (int)G[to].size(), false});
        G[to].push_back({from, 0, (int)G[from].size()-1, true});
    }

    // sからtへ流量fを流す
    T maxflow(int s, int t, T f = 1LL<<30) {
        T flow = 0;
        while(1) {
            bfs(s);
            if(level[t] < 0) return flow;
            iter.assign(G.size(), 0);
            T tmp;
            while((tmp = dfs(s, t, f)) > 0) flow += tmp;
        }
    }

    // sからtへ1流す
    T flow(int s, int t) {
        bfs(s);
        if(level[t] < 0) return 0;
        iter.assign(G.size(), 0);
        return dfs(s, t, 1);
    }
    // 始点，終点tのフローで辺e=(from,to)の容量を1増やしたときの最大流の変化
    // 並列辺はたぶんバグる
    T add(int from, int to, int s, int t) {
        for(auto &e: G[from]) {
            if(e.to == to && !e.isrev) {
                e.cap++;
                break;
            }
        }
        return flow(s, t);
    }
    // 始点s，終点tのフローで辺e=(from,to)の容量を1減らしたときの最大流の変化
    // 並列辺はたぶんバグる
    T sub(int from, int to, int s, int t) {
        for(auto &e: G[from]) {
            if(e.to == to && !e.isrev) {
                T diff = 0;
                // 辺(from,to)で容量いっぱいに流れている
                if(e.cap == 0) {
                    // 残余グラフでfrom→toのパスがない
                    if(flow(from, to) == 0) {
                        flow(t, to);
                        flow(from, s);
                        diff = -1;
                    }
                    G[e.to][e.rev].cap--;
                } else {
                    e.cap--;
                }
                return diff;
            }
        }
        assert(false); // 存在しない辺を減らそうとした
    }

    friend ostream &operator <<(ostream& out, const dinic& a){
        out << endl;
        for(int i = 0; i < (int)a.G.size(); i++) {
            for(auto &e : a.G[i]) {
                if(e.isrev) continue;
                auto &rev_e = a.G[e.to][e.rev];
                out << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
            }
        }
        return out;
    }
};

int main(void) {
    ll h, w;
    cin >> h >> w;
    vector<string> v(h);
    REP(i, h) cin >> v[i];

    dinic<ll> graph(h*w+h*(w-1)+(h-1)*w+2);
    ll s = h*w+h*(w-1)+(h-1)*w, t = s+1;
    ll num = h*w, ret = 0;

    REP(i, h) REP(j, w) {
        if(v[i][j] == '#') {
            graph.add_edge(s, i*w+j, 1);
            graph.add_edge(i*w+j, t, 1);
        } else {
            graph.add_edge(s, i*w+j, 0);
            graph.add_edge(i*w+j, t, 0);
        }
    }
    REP(i, h) {
        REP(j, w-1) {
            // (i,j)と(i,j+1)が両方横 → 1得る
            if(v[i][j]=='.' || v[i][j+1]=='.') continue;
            ret++;
            graph.add_edge(s, num, 1);
            graph.add_edge(num, i*w+j, INF);
            graph.add_edge(num, i*w+j+1, INF);
            num++;
        }
    }
    REP(j, w) {
        REP(i, h-1) {
            // (i,j)と(i+1,j)が両方縦 → 1得る
            if(v[i][j]=='.' || v[i+1][j]=='.') continue;
            ret++;
            graph.add_edge(num, t, 1);
            graph.add_edge(i*w+j, num, INF);
            graph.add_edge((i+1)*w+j, num, INF);
            num++;
        }
    }

    cout << graph.maxflow(s, t) - ret << endl;
    // dump(graph);

    return 0;
}

```