#include <iostream>
#include <fstream>
#include <queue>
#if 1
#define pv(x) cout<<#x<<" = "<<x<<"; ";cout.flush()
#define pn cout<<endl
#else
#define pv(x)
#define pn
#endif
using namespace std;
ifstream in("barbar.in");
ofstream out("barbar.out");
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
const int NMax = 1e3 + 5;
int dx[4] = {-1,1,0,0}, dy[4] = {0,0,-1,1};
int N,M;
char a[NMax][NMax];
bool vis[NMax][NMax];
int distDragon[NMax][NMax];
// a[i][j] - valoarea caracter din input din celula (i,j);
// vis[i][j] = true, daca celula (i,j) a fost vizitata la parcurgerea curenta;
// distDragon[i][j] = distanta minima de la celula (i,j) la un dragon;
struct queueElement {
int x,y,pasi;
queueElement(int _x = 0,int _y = 0,int _pasi = 0): x(_x), y(_y), pasi(_pasi) {}
};
bool canEscape(int,int,int,int,int);
int main() {
in>>N>>M;
int xStart = 0,yStart = 0,xEnd = 0,yEnd = 0;
queue< queueElement > Q;
for (int i=1;i <= N;++i) {
in>>(a[i]+1);
for (int j=1;j <= M;++j) {
if (a[i][j] == 'D') {
// celulele in care se afla dragoni se introduc in coada ca pozitii de start;
// pentru a construi distDragon;
Q.push( queueElement(i,j,0) );
distDragon[i][j] = 0;
vis[i][j] = true;
}
else if (a[i][j] == 'I') {
xStart = i;
yStart = j;
}
else if (a[i][j] == 'O') {
xEnd = i;
yEnd = j;
}
}
}
// se relizeaza o parcurgere lee din fiecare celula care contine un dragon;
// maxDist = maximul dintre distDragon[i][j];
int maxDist = 0;
while (Q.size()) {
queueElement e = Q.front();
Q.pop();
for (int k=0;k < 4;++k) {
int nx = e.x + dx[k],
ny = e.y + dy[k];
// daca se iese din matrice, dam de un perete sau daca am mai vizitat celula;
if (nx < 1 || nx > N || ny < 1 || ny > M || a[nx][ny] == '*' || vis[nx][ny]) {
continue;
}
distDragon[nx][ny] = e.pasi + 1;
vis[nx][ny] = true;
Q.push( queueElement(nx,ny,e.pasi + 1) );
maxDist = max(maxDist,distDragon[nx][ny]);
}
}
// se cauta binar solutia;
int pw = 1, ans = 0;
for (;pw <= maxDist;pw <<= 1) ;
pw >>= 1;
while (pw) {
if ( canEscape(xStart,yStart,xEnd,yEnd, ans + pw) ) {
ans += pw;
}
pw >>= 1;
}
// ca raspunsul sa nu existe, ans trebuie sa fie 0,
// dar raspunsul poate exista cu ans fiind 0;
if (ans == 0 && canEscape(xStart,yStart,xEnd,yEnd,0) == false) {
out<<"-1\n";
}
else {
out<<ans<<'\n';
}
return 0;
}
// functia determina daca Paftanie poate scapa mergand doar prin
// celule care au distanta minima mai mare sau egala cu minDist;
bool canEscape(int xStart,int yStart,int xEnd,int yEnd,int minDist) {
if (distDragon[xStart][yStart] < minDist) {
return false;
}
for (int i=1;i <= N;++i) {
for (int j=1;j <= M;++j) {
vis[i][j] = false;
}
}
queue< pair<int,int> > Q;
Q.push( mp(xStart,yStart) );
while (Q.size()) {
pair<int,int> p = Q.front();
Q.pop();
if (p.first == xEnd && p.second == yEnd) {
return true;
}
for (int k=0;k < 4;++k) {
int nx = p.first + dx[k],
ny = p.second + dy[k];
if (vis[nx][ny] || distDragon[nx][ny] < minDist) {
continue;
}
// daca se iese din matrice sau daca dam de un perete;
if (nx < 1 || nx > N || ny < 1 || ny > M || a[nx][ny] == '*') {
continue;
}
vis[nx][ny] = true;
Q.push( mp(nx,ny) );
}
}
return false;
}