#include <bits/stdc++.h>
#define FOR(i,a,b) for(ut i=(a);i<(ut)(b);i++)
#define REP(i,b) FOR(i,0,b)
#define ALL(c) c.begin(),c.end()
#define PB push_back
#define cat cout << __LINE__ << endl;
using namespace std;
typedef long long LL;
typedef double ld;
typedef int ut;
typedef complex<int> cli;
typedef vector<ut> VI;
typedef pair<ut,ut> pr;
typedef pair<ut,pr> ppr;
typedef vector<pr> Vpr;
typedef vector<ppr> Vppr;
typedef priority_queue<pr,Vpr> PQ;
const int INF=1<<30;
int H,W;
int reconv(int x){x-=2;cout << x/(H*W) <<" " << x%(H*W)/W <<" " << x%(H*W)%W << endl;}
struct Edge{
public:
	int to,cost,cp;
	shared_ptr<Edge> rev;
	Edge(){to=0;cost=0;cp=0;}
	Edge(int a,int b,int c);
	void add(int x){
		cp+=x;
	}
	void flow(int amount){
		add(-amount);
		rev->add(amount);
	}
	bool usable(){
		return cp>=1;
	}	
};
Edge vo;
Edge::Edge(int t,int c,int cp):to(t),cost(c),cp(cp){
}
void unite(shared_ptr<Edge> a,shared_ptr<Edge> b){
	a->rev=b;
	b->rev=a;
}

queue<int> qu;
class Graph{
	int nodeSize,edgeSize;
	vector<int> dist;
	vector<vector<shared_ptr<Edge>>> edges;
public: 
	void add(int a,int b,int cost,int cp){
		
		edges[a].PB(make_shared<Edge>(b,cost,cp));
		edges[b].PB(make_shared<Edge>(a,cost,0));
		unite(edges[a].back(),edges[b].back());
	}
	Graph(){}
	Graph(int x):nodeSize(x){
		
		edges=vector<vector<shared_ptr<Edge>>>(nodeSize);
		dist=VI(nodeSize);
	}
	void distInit(int s){
		REP(i,nodeSize){
			dist[i]=INF;
		}
		dist[s]=0;
	}
	int searching(int now,int e,int capacity){
	//	cout << now <<" ";
	//	reconv(now);
		if(capacity<=0) return 0;
		if(now==e) return capacity;
		//if(dist[now]>=dist[e]) return 0;
		int flowed=0;
		REP(i,edges[now].size()){
			auto ed= edges[now][i];
		//	reconv(ed->to);
			if(!ed->usable()) continue;
			if(dist[now]-1 != dist[ed->to]) continue;
			int nflow=searching(ed->to,e,min(capacity-flowed,ed->cp));
			if(nflow){
				flowed+=nflow;
				ed->flow(nflow);
			}
			
			if(flowed) return flowed;
		}
		return flowed;
	}
	bool bfs(int s,int e){
		distInit(s);
		queue<int> qu;
		qu.push(s);
		while(!qu.empty()){
			int now=qu.front();
	//		// cout << now << endl;
			qu.pop();
			REP(i,edges[now].size()){;
				auto ed=edges[now][i];
				if(!ed->rev->usable()) continue;
				if(dist[ed->to]==INF){
					qu.push(ed->to);
					dist[ed->to]=dist[now]+1;
				}
			}
		}
		
		return dist[e]!=INF;
	}
	int maximumFlow(int s,int e){
		int ans=0,bef;
		while(bfs(e,s)){
			ans+=searching(s,e,INF);
			if(ans==bef) break;
//			cout << ans << endl;
			bef=ans;
		}
		return ans;
	}
};
const int SIZE=101;
int dy[]={0,1,0,-1},dx[]={1,0,-1,0};
int maps[SIZE][SIZE];
Graph graph;
int conv(int a,int b,int c){return a*W+b+H*W*c+2;}
bool isSafe(int y,int x){
	return 0<=y && y<H && 0<=x && x<W;
}
int main(){
	cin >> H >> W;
	graph=Graph(SIZE*SIZE*3+3);
	REP(i,H) {
		string s;
		cin >> s;
		REP(j,W){
			maps[i][j]=s[j]=='X';
			if(maps[i][j] &&(i==0 || j==0 || i==H-1 || j==W-1)){
				cout << -1 << endl;
				return 0;
			}
	//		cout << maps[i][j];
		}		
//		cout << endl;
	}
	REP(i,H) REP(j,W) {
		graph.add(conv(i,j,1),conv(i,j,0),0,1);
		if(maps[i][j]){
			graph.add(0,conv(i,j,0),0,4);
		}
		REP(k,4){
			if(!isSafe(i+dy[k],j+dx[k])){
				graph.add(conv(i,j,0),1,0,1);
			} 
			else{
		//		cout << i <<" " << j <<" " << i+dy[k] <<" " << j+dx[k] << endl;
		//		cout << conv(i,j,0) << " " << conv(i+dy[k],j+dx[k],1) << endl;
				graph.add(conv(i,j,0),conv(i+dy[k],j+dx[k],1),0,1);
				graph.add(conv(i+dy[k],j+dx[k],0),conv(i,j,1),0,1);
			}
		}
	
	}
	cout << graph.maximumFlow(0,1) << endl;


	return 0;
}

Measured memory_bytes: 17152