#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;

int H, W;
char board[15][15];
using Board = map<string, map<int, int> >;
void chmax(int &A, int B) { A = max(A, B); }

string get_uni(string s, int x, int mode) {
    vector<int> v(10), checked(10); iota(v.begin(), v.end(), 0);
    if(mode == 1) {
        if(x != 0 && isdigit(s[x]) && isdigit(s[x-1])) {
            int a = s[x] - '0', b = s[x-1] - '0';
            v[a] = b;
        }
        else {
            bool exist_num = false;
            if(x != 0 && isdigit(s[x-1])) {
                exist_num = true;
                s[x] = s[x-1];
            }
            if(isdigit(s[x])) {
                exist_num = true;
            }

            if(!exist_num) {
                s[x] = '8';
            }
        }
    }

    string ret = "";
    int id = 0;
    for(int i=0; i<W; i++) {
        if(isdigit(s[i])) {
            int val = v[ s[i] - '0' ];
            if(!checked[val]) checked[val] = ++id;
            ret += (char)('0' + checked[val]);
        }
        else {
            ret += s[i];
        }
    }
    return ret;
}

bool valid(string s) {
    int pre = -1;
    for(auto c : s) {
        if(isdigit(c)) {
            if(pre == -1) pre = c - '0';
            else if(pre != c - '0') return false;
        }
    }
    return true;
}

string to_bin(int N) {
    string ret = "";
    for(int i=0; i<W; i++, N>>=1) {
        int c = (N & 1);
        ret += (char)('0' + c);
    }
    return ret;
}

int main() {
    scanf("%d%d", &H, &W);
    for(int i=0; i<H; i++) {
        for(int j=0; j<W; j++) {
            scanf(" %c", &board[i][j]);
        }
    }

    string emp_str(W, '.');
    Board cur, nxt;
    cur[emp_str][0] = 0;

    for(int pos=0; pos<H*W; pos++) {
        int row = pos / W, col = pos % W;
        char c = board[row][col];
        for(auto x : cur) {
            string uni = x.first;
            for(auto y : cur[uni]) {
                int bit = y.first, pre = y.second;
                // printf("row = %d, col = %d, dp[%s][%s] = %d\n", row+1, col+1, uni.c_str(), to_bin(bit).c_str(), pre);

                int base = bit - ((bit >> col & 1) << col);

                // paint (black)
                if(c == '#' || c == '?') {
                    // printf("cond 1: row = %d, col = %d\n", row+1, col+1);
                    if(col == 0 || (uni[col] != uni[col-1] || !isdigit(uni[col]))) {
                        string tmp = uni;

                        // printf("tmp = %s, ", tmp.c_str());
                        tmp = get_uni(tmp, col, 1);
                        // printf("nxt = %s\n", tmp.c_str());
                    
                        int nbit = base | (1 << col);
                        chmax(nxt[tmp][nbit], pre + 1);
                    }
                }

                // paint (white)
                if(c == '.' || c == '?') {
                    // printf("cond 2: row = %d, col = %d\n", row+1, col+1);

                    bool ok = true;
                    if(row != 0 && !(bit >>  col      & 1)) ok = false;
                    if(col != 0 && !(bit >> (col - 1) & 1)) ok = false;

                    char target = uni[col];
                    int cnt = 0;
                    for(int i=0; i<W; i++) cnt += (uni[i] == target);
                    if(isdigit(target) && cnt == 1 && W != 1) ok = false;

                    if(ok) {
                        string tmp = uni;
                        tmp[col] = '.';
                        tmp = get_uni(tmp, col, 0);

                        int nbit = base;
                        chmax(nxt[tmp][nbit], pre);
                    }
                }
            }
        }
        cur.clear();
        swap(cur, nxt);
    }

    int ans = -1;
    for(auto x : cur) {
        string uni = x.first;
        if(!valid(uni)) continue;
        
        for(auto y : cur[uni]) {
            int val = y.second;
            chmax(ans, val);
        }
    }
    printf("%d\n", ans);
    return 0;
}


Measured memory_bytes: 4200