#include <queue>
#include <type_traits>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>
#include <limits>
#include <iostream>
namespace lc {
template <class CapacityType>
struct EdgeWithCapacity {
	int to;
	CapacityType capacity;
	EdgeWithCapacity() : to(0), capacity() { }
	EdgeWithCapacity(int to, const CapacityType &capacity)
		: to(to), capacity(capacity)
	{ }
};
}
namespace lc {
template <typename EdgeType>
class AdjacencyList {
public:
	typedef std::vector<EdgeType> ListType;
private:
	std::vector<ListType> m_lists;
public:
	explicit AdjacencyList(int n = 0)
		: m_lists(n)
	{ }
	int size() const { return m_lists.size(); }
	template <typename... Args>
	void add_edge(int u, Args&&... args){
		m_lists[u].emplace_back(args...);
	}
	const ListType &operator[](int u) const { return m_lists[u]; }
	ListType &operator[](int u){ return m_lists[u]; }
};
}
namespace lc {
template <class EdgeType>
struct HasWeight {
private:
	static std::false_type check(...);
public:
	static const bool value = decltype(check(EdgeType()))::value;
};
}
namespace lc {
template <class EdgeType>
struct ResidualEdge : public EdgeType {
	int rev;
	template <class... Args>
	ResidualEdge(int rev, Args&&... args)
		: EdgeType(args...)
		, rev(rev)
	{ }
};
template <class EdgeType>
class ResidualAdjacencyList
	: public AdjacencyList<ResidualEdge<EdgeType>>
{
public:
	explicit ResidualAdjacencyList(int n = 0)
		: AdjacencyList<ResidualEdge<EdgeType>>(n)
	{ }
};
template <class EdgeType>
auto make_residual(const AdjacencyList<EdgeType> &graph)
	-> typename std::enable_if<
		!HasWeight<EdgeType>::value, ResidualAdjacencyList<EdgeType>>::type
{
	typedef decltype(EdgeType().capacity) capacity_type;
	const int n = graph.size();
	ResidualAdjacencyList<EdgeType> result(n);
	for(int u = 0; u < n; ++u){
		for(const auto &e : graph[u]){
			const int v = e.to;
			const int rev_u = result[v].size();
			const int rev_v = result[u].size();
			result[u].emplace_back(rev_u, e);
			result[v].emplace_back(rev_v, e);
			result[v].back().to = u;
			result[v].back().capacity = capacity_type();
		}
	}
	return result;
}
}
namespace lc {
template <class EdgeType>
auto maxflow_dinic(
	int source, int sink, ResidualAdjacencyList<EdgeType> &graph)
	-> decltype(EdgeType().capacity)
{
	typedef decltype(EdgeType().capacity) capacity_type;
	const capacity_type inf = std::numeric_limits<capacity_type>::max();
	const int n = graph.size();
	capacity_type flow = 0;
	while(true){
		std::vector<int> level(n, -1);
		std::queue<int> q;
		level[source] = 0;
		q.push(source);
		while(!q.empty()){
			const int u = q.front();
			q.pop();
			for(const auto &e : graph[u]){
				const int v = e.to;
				if(e.capacity <= 0 || level[v] >= 0){ continue; }
				level[v] = level[u] + 1;
				q.push(v);
			}
		}
		if(level[sink] < 0){ break; }
		std::vector<size_t> iteration(n, 0);
		while(true){
			std::function<capacity_type(int, capacity_type)> dfs =
				[&](int u, capacity_type limit) -> capacity_type {
					if(u == sink){ return limit; }
					for(; iteration[u] < graph[u].size(); ++iteration[u]){
						auto &e = graph[u][iteration[u]];
						const int v = e.to;
						if(e.capacity <= 0 || level[u] >= level[v]){ continue; }
						const capacity_type diff =
							dfs(v, std::min(e.capacity, limit));
						if(diff > 0){
							e.capacity -= diff;
							graph[v][e.rev].capacity += diff;
							return diff;
						}
					}
					return 0;
				};
			const auto f = dfs(source, inf);
			if(f <= 0){ break; }
			flow += f;
		}
	}
	return flow;
}
}
using namespace std;
using Edge = lc::EdgeWithCapacity<int>;
const int INF = 1000000000;
int main(){
	ios_base::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	vector<string> field(n);
	for(int i = 0; i < n; ++i){ cin >> field[i]; }
	for(int j = 0; j < m; ++j){
		if(field[0][j] == 'X' || field[n - 1][j] == 'X'){
			cout << -1 << endl;
			return 0;
		}
	}
	for(int i = 0; i < n; ++i){
		if(field[i][0] == 'X' || field[i][m - 1] == 'X'){
			cout << -1 << endl;
			return 0;
		}
	}
	const int source = 2 * n * m, sink = source + 1;
	lc::AdjacencyList<Edge> graph(2 * n * m + 2);
	for(int i = 1; i < n; ++i){
		for(int j = 1; j < m; ++j){
			const int x = (i - 1) * m + j;
			const int y = i * m + (j - 1);
			const int z = i * m + j;
			graph.add_edge(x + n * m, z, INF);
			graph.add_edge(z + n * m, x, INF);
			graph.add_edge(y + n * m, z, INF);
			graph.add_edge(z + n * m, y, INF);
		}
	}
	for(int i = 0; i < n; ++i){
		for(int j = 0; j < m; ++j){
			const int x = i * m + j;
			graph.add_edge(x, x + n * m, 1);
			if(i == 0 || i == n - 1 || j == 0 || j == m - 1){
				graph.add_edge(x + n * m, sink, INF);
			}
			if(field[i][j] == 'X'){
				graph.add_edge(source, x + n * m, INF);
			}
		}
	}
	auto residual = lc::make_residual(graph);
	cout << lc::maxflow_dinic(source, sink, residual) << endl;
	return 0;
}


Measured memory_bytes: 4284