#include <bits/stdc++.h>
using namespace std;

class UF{
public:
  int V;
  vector<int> par,rnk,sz;
  UF(){}
  UF(int V):V(V),par(V),rnk(V,0),sz(V,1){for(int i=0;i<V;i++)par[i]=i;}
  
  int find(int x){
    assert(x < V);
    if(par[x]==x)return x;
    return par[x]=find(par[x]);
  }
  
  void unite(int x,int y){
    x=find(x), y=find(y);
    if(x==y)return;
    if(rnk[x]<rnk[y])par[x]=y, sz[y] += sz[x];
    else{
      par[y]=x;
      sz[x] += sz[y];
      if(rnk[x]==rnk[y])rnk[x]++;
    }
  }
  
  bool same(int x,int y){return find(x)==find(y);}
  
  int size(int x){return sz[find(x)];}
};

int h, w;
string s[11];

unordered_set<int> can_go(int &A, int &pS, int &S, UF &uf){ // SのAからiに行けるかどうか(ufでワープ可能)
  
  int C[2][11], used[2][11];

  for(int i=0;i<2;i++)
    for(int j=0;j<w;j++) used[i][j] = 0;
  
  for(int i=0;i<w;i++) C[0][i] = pS >> i & 1;
  for(int i=0;i<w;i++) C[1][i] = S >> i & 1;
  
  typedef pair<int,int> P;
  
  queue<P> q;
  
  used[1][A] = 1;
  q.push(P( 1, A ));
    
  while(!q.empty()){
    
    P tmp = q.front(); q.pop();
    
    int idx = tmp.first;
    int node = tmp.second;
    
    int nidx = idx;
    int nnode = node + 1;
    
    if( nnode < w && C[nidx][nnode] && !used[nidx][nnode] ){
      used[nidx][nnode] = 1;
      q.push(P( nidx, nnode ));
    }
    
    if( idx == 0 ){
      
      nidx = idx + 1;
      nnode = node;
      
      if( C[nidx][nnode] && !used[nidx][nnode] ){
	used[nidx][nnode] = 1;
	q.push(P( nidx, nnode ));
      }
      
      for(int i=0;i<w;i++){
	
	if( uf.same( node, i ) == 0 ) continue;
	
	nidx = 0;
	nnode = i;
	
	if( C[nidx][nnode] && !used[nidx][nnode] ){
	  used[nidx][nnode] = 1;
	  q.push(P( nidx, nnode ));
	}

      }
      
    }else{
      
      nidx = idx - 1;
      nnode = node;
      
      if( C[nidx][nnode] && !used[nidx][nnode] ){
	used[nidx][nnode] = 1;
	q.push(P( nidx, nnode ));
      }
      
    }
    
  }

  unordered_set<int> res;
  
  for(int i=A+1;i<w;i++)
    if( used[1][i] ) res.insert(i);
  
  return res;
}

bool roop(int &A, int &pS, int &S, UF &uf){ // Aの上のグループと同じところを繋いでしまうかどうか(ufでワープ可能)

  int C[2][11], used[2][11];
  
  for(int i=0;i<2;i++)
    for(int j=0;j<w;j++) used[i][j] = 0;
  
  for(int i=0;i<w;i++) C[0][i] = pS >> i & 1;
  for(int i=0;i<w;i++) C[1][i] = S >> i & 1;
  
  typedef pair<int,int> P;
  
  queue<P> q;
  
  used[1][A] = 1;
  q.push(P( 1, A ));
  
  while(!q.empty()){
    
    P tmp = q.front(); q.pop();
    
    int idx = tmp.first;
    int node = tmp.second;
    
    if( idx == 0 && node == A ) continue;
    
    if( node != A && idx == 1 && C[0][node] && uf.same( A, node ) == 1 ) return true;
    
    int nidx = idx;
    int nnode = node + 1;
    
    if( nnode < w && C[nidx][nnode] && !used[nidx][nnode] ){
      used[nidx][nnode] = 1;
      q.push(P( nidx, nnode ));
    }
    
    if( idx == 0 ){
      
      nidx = idx + 1;
      nnode = node;
      
      if( C[nidx][nnode] && !used[nidx][nnode] ){
	used[nidx][nnode] = 1;
	q.push(P( nidx, nnode ));
      }
      
      for(int i=0;i<w;i++){
	
	if( uf.same( node, i ) == 0 ) continue;
	
	nidx = 0;
	nnode = i;
	
	if( C[nidx][nnode] && !used[nidx][nnode] ){
	  used[nidx][nnode] = 1;
	  q.push(P( nidx, nnode ));
	}

      }
      
    }else{
      
      nidx = idx - 1;
      nnode = node;
      
      if( C[nidx][nnode] && !used[nidx][nnode] ){
	used[nidx][nnode] = 1;
	q.push(P( nidx, nnode ));
      }
      
    }
    
  }

  return false;
}

bool AB(int &A, int &B, int &S){ // S上で、A と B が黒色で繋がっているかどうか
  
  for(int i=A;i<=B;i++)
    if( ( S >> i & 1 ) == 0 ) return false;
  
  return true;
}

typedef unsigned long long ull;

ull UFtoULL(UF &uf){
  
  ull res = 0, x = 1;
  
  for(int i=0;i<w;i++){
    
    for(int j=i+1;j<w;j++){
      
      if( uf.same( i, j ) ) res += x;
      
      x *= 2;
      
    }
    
  }    
  
  return res;
}

UF ULLtoUF(ull A){
  
  UF res(w);
  ull cnt = 1;
  
  for(int i=0;i<w;i++){
    
    for(int j=i+1;j<w;j++){
      
      if( A >> cnt & 1 ) res.unite( i, j );
	
      cnt++;
    }
    
  }
  
  return res;
}

unordered_map<ull,int> memo[11][1<<11];
char c[2] = {'.', '#'};

int dfs(int y, int pS, UF uf){

  if( y == h ){
    
    for(int i=0;i<w;i++){
      
      if( !( pS >> i & 1 ) ) continue;
      
      for(int j=i+1;j<w;j++){
	
	if( !( pS >> j & 1 ) ) continue;
	
	if( uf.same( i, j ) == 0 ) return -1e8;
	
      }
      
    }
    
    return 0;
  }
  
  if( memo[y][pS].count(UFtoULL(uf)) ) return memo[y][pS][UFtoULL(uf)];
  
  int res = -1e8;
  
  for(int S = 0; S < ( 1 << w ); S++ ){
    
    int flag = 1;
    
    for(int i=0;i<w;i++){ // 矛盾がないか判定
      if( s[y][i] == '?' ) continue;
      if( c[S>>i&1] != s[y][i] ) flag = 0;
    }

    if( flag == 0 ) continue;

    for(int i=0;i<w;i++){ // 白色が隣合わないか判定
      if( ( pS >> i & 1 ) == 0 && ( S >> i & 1 ) == 0 ) flag = 0;
      if( i == w - 1 ) continue;
      if( ( S >> i & 1 ) == 0 && ( S >> ( i + 1 ) & 1 ) == 0 ) flag = 0;
    }
    
    if( flag == 0 ) continue;
    
    if( y != 0 ){
      
      for(int i=0;i<w;i++){ // 分断されないか判定
	if( ( pS >> i & 1 ) == 0 ) continue;
	if( ( S >> i & 1 ) == 1 ) continue;
	int f = 0;
	for(int j=0;j<w;j++){
	  if( ( pS >> j & 1 ) == 0 ) continue;
	  if( ( S >> j & 1 ) == 0 ) continue;
	  if( uf.same( i, j ) == 1 ) f = 1;
	}
	if( f == 0 ) flag = 0;
      }

      if( flag == 0 ) continue;
      
    }

    if( y != 0 ){
    
      for(int i=0;i<w;i++){ // 閉路を作らないか判定
      
	if( ( pS >> i & 1 ) == 0 ) continue;
	if( ( S >> i & 1 ) == 0 ) continue;

	if( roop( i, pS, S, uf ) == 1 ) flag = 0;

      }

      if( flag == 0 ) continue;
      
    }

    UF nuf(w);
    
    for(int i=0;i<w;i++){ // どちらも存在する部分だけufからnufにコピー
      
      if( ( pS >> i & 1 ) == 0 ) continue;
      if( ( S >> i & 1 ) == 0 ) continue;
      
      for(int j=i+1;j<w;j++){
	
	if( ( pS >> j & 1 ) == 0 ) continue;
	if( ( S >> j & 1 ) == 0 ) continue;
	
	if( uf.same( i, j ) == 1 ) nuf.unite( i, j );
	
      }
      
    }

    for(int i=0;i<w;i++){ // 繋がる部分を連結にする
      
      if( ( S >> i & 1 ) == 0 ) continue;
      
      unordered_set<int> node = can_go( i, pS, S, uf );
	
      for(int j=i+1;j<w;j++){
	
	if( ( S >> j & 1 ) == 0 ) continue;
	
	if( y != 0 && node.count(j) == 1 ) nuf.unite( i, j );
	if( y == 0 && AB( i, j, S ) == 1 ) nuf.unite( i, j );
	
      }
      
    }
    
    res = max( res, dfs( y + 1, S, nuf ) + __builtin_popcount(S) );
    
  }
  
  return memo[y][pS][UFtoULL(uf)] = res;
}

int main(){
  
  cin>>h>>w;
  
  for(int i=0;i<h;i++) cin>>s[i];
  
  if( w == 1 && s[h-1] == "." ) h--;
  
  int ans = dfs( 0, (1<<w)-1, UF(w) );
  
  if( ans < 0 ) cout<<-1<<endl;
  else cout<<ans<<endl;
    
  return 0;
}



Measured memory_bytes: 5240