#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define N 1001
int R, C, d[N][N];
bool used[N][N]; // avem nevoie sa stim daca am procesat casuta (i, j)
char v[N][N];
int xx[4] = {-1, 0, 1, 0};
int yy[4] = {0, 1, 0, -1}; // le vom folosi la bfs/lee ca sa nu avem 4 ifuri ci facem un for in schimb
// o alta chestie: struct
// sau hai sa o denumim cell
// deci un cell mentine x si y, adica linia si coloana
struct cell {
int x, y;
cell() {};// e o fctie care initializeaza celula cand o declari goala
cell(int _x, int _y) { // o fctie care o initializeaza cand ii dai parametri
// de ex cell x(3,4); va crea o celula cu x = 3 si y = 4
x = _x;
y = _y;
}
};
cell Q[2000010];
int first, last;
// mai avem nevoie de o coada
void read() {
freopen ("barbar.in", "r", stdin);
scanf ("%d %d\n", &R, &C);
int i, j;
for (i = 1; i <= R; ++i)
scanf ("%s\n", v[i] + 1);
}
inline bool isOk(int i, int j) { // verifica daca (i, j) e in matrice
if (i >= 1 && i <= R && j >= 1 && j <= C)
return true;
return false;
}
// BreadthFirstSearch
void bfs() {
// punem in coada toti dragonii
//queue<cell> Q; // asta e o coada, stii ce e coada?NU
// e o structura care imita coada de la paine
// cand vine un nou element, se aseaza la final, cand cel care a cumparat painea pleaca
//trebuie sa punem toti dragonii in coada
int i, j;
first = 1; last = 0;
for (i = 1; i <= R; ++i)
for (j = 1; j <= C; ++j)
if (v[i][j] == 'D')
d[i][j] = 0,//distanta pana la un dragon e 0 pt ca ai deja dragon in (i, j)
used[i][j] = true,
Q[++last] = cell(i, j);//Q.push( cell(i, j) ); //push adauga la finalul cozii
// acum facem bfs-ul propriu-zis
while (first <= last) { //cat timp mai avem elemente in coada
cell u = Q[first++]; // luam prima celula (cea care trebuie sa 'cumpere' paine')
used[u.x][u.y] = true;// am procesat casuta
// si acum ne uitam la casutele adiacente pe care nu le-am procesat deja
for (int ii = 0; ii < 4; ++ii) { // merg pe cele 4 casute
cell new_u( u.x + xx[ii], u.y + yy[ii] );
//verific ca celula sa nu iasa din matrice
if (isOk(new_u.x, new_u.y))
if (v[new_u.x][new_u.y] != '*' && !used[new_u.x][new_u.y]) { // daca nu e procesata
d[new_u.x][new_u.y] = d[u.x][u.y] + 1;
Q[++last] = new_u;
//Q.push( new_u ); // adaugam in coada
}
}
}
}
bool findPath(int minDistance) {
memset (used, 0, sizeof(used)); // setez used la 0
// iar facem BFS, dar acum il facem de la I la O
//queue<cell> Q;
// punem in Q celula lui I
first = 1; last = 0;
int i, j;
cell dest;
for (i = 1; i <= R; ++i)
for (j = 1; j <= C; ++j)
if (v[i][j] == 'I')
used[i][j] = true,
Q[++last] = cell(i, j); //.push( cell(i, j) );
else if (v[i][j] == 'O')
dest = cell(i, j);
cell u, new_u;
while (first <= last) {
u = Q[first++];
used[u.x][u.y] = true;
if (u.x == dest.x && u.y == dest.y) // am ajuns la destinatie, deci exista drum
return true;
for (int ii = 0; ii < 4; ++ii) {
new_u = cell(u.x + xx[ii], u.y + yy[ii]);
if (isOk(new_u.x, new_u.y) && v[new_u.x][new_u.y] != '*' && !used[new_u.x][new_u.y]) {
if (d[new_u.x][new_u.y] >= minDistance)
Q[++last] = new_u;//Q.push(new_u);
}
}
}
return false;
}
void solve() {
// prima etapa e sa calculam d[i][j] = distanta minima pana la cel mai apropiat dragon
bfs();
// acum trecem la partea a2a unde trebuie sa cautam binar rezultatul
int i, cnt;
bool found = false;
for (i = 0, cnt = (1 << 10); cnt; cnt >>= 1)
if (findPath(i + cnt))
i += cnt,
found = true;
freopen ("barbar.out", "w", stdout);
if (!found)
printf ("-1\n");
else
printf ("%d\n", i);
// deci eu caut binar cel mai mare i pentru care exista drum
// functia findPath imi va spune daca exista drum
}
int main() {
read();
// cand ai o problema care va avea o sursa mare e bine sa verifici pasii majori
solve();
}