#include <fstream>
#include <vector>
#include <queue>
#include <cmath>
using namespace std;
ifstream cin("barbar.in");
ofstream cout("barbar.out");
const int INF = 2e9;
const int MAX = 1005;
int di[4] = {0, 0, 1, -1};
int dj[4] = {1, -1, 0, 0};
vector < vector < bool > > used(MAX, vector < bool > (MAX));
bool is_good(int i, int j, int n, int m) {
return i >= 1 and j >= 1 and i <= n and j <= m;
}
void bfs(pair < int, int > poz, vector < vector < int > > &dist_drag, vector < string > &v, int n, int m) {
queue < pair < int, int > > q;
dist_drag[poz.first][poz.second] = 0;
q.push(poz);
while (!q.empty()) {
auto cur = q.front();
q.pop();
for (int i = 0; i < 4; i ++) {
int row = cur.first + di[i];
int col = cur.second + dj[i];
int next_dist = dist_drag[cur.first][cur.second] + 1;
if (!is_good(row, col, n, m)) continue;
if (next_dist >= dist_drag[row][col]) continue;
if (v[row][col] == 'D' or v[row][col] == '*') continue;
dist_drag[row][col] = next_dist;
q.push({row, col});
}
}
}
void dfs(int min_dist, pair < int, int > me, pair < int, int > destination, int n, int m,
bool &found_path, vector < string > &v, vector < vector < int > > &dist_drag) {
if (found_path) return;
if (dist_drag[me.first][me.second] < min_dist or
v[me.first][me.second] == '*' or v[me.first][me.second] == 'D') {
return;
}
if (me == destination) {
found_path = true;
return;
}
for (int i = 0; i < 4; i ++) {
int row = me.first + di[i];
int col = me.second + dj[i];
if (!is_good(row, col, n, m)) continue;
if (used[row][col]) continue;
used[row][col] = true;
dfs(min_dist, {row, col}, destination, n, m, found_path, v, dist_drag);
}
}
void get_dist_drag(int n, int m, queue < pair < int, int > > &q,
vector < vector < int > > &dist_drag, vector < string > &v) {
while (!q.empty()) {
auto cur_drag = q.front();
q.pop();
bfs(cur_drag, dist_drag, v, n, m);
}
}
int main(int argc, char const *argv[]) {
int n, m;
cin >> n >> m;
vector < string > v (n + 1);
for (int i = 1; i <= n; i ++) {
cin >> v[i];
v[i] = '*' + v[i];
}
queue < pair < int, int > > q;
pair < int, int > me;
pair < int, int > destination;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= m; j ++) {
if (v[i][j] == 'D') {
q.push({i, j});
}
else if (v[i][j] == 'I') {
me = {i, j};
}
else if (v[i][j] == 'O') {
destination = {i, j};
}
}
}
vector < vector < int > > dist_drag (n + 1, vector < int > (m + 1, INF));
get_dist_drag(n, m, q, dist_drag, v);
int min_dist = 0;
int sol = -1;
for (int i = log2(n + m + 1); i >= 0; i --) {
if ((1 << i) > n + m + 1) continue;
bool found_path = false;
for (int j = 1; j <= n; j ++) {
for (int k = 1; k <= m; k ++) {
used[j][k] = false;
}
}
used[me.first][me.second] = true;
dfs(min_dist + (1 << i), me, destination, n, m, found_path, v, dist_drag);
if (found_path) {
min_dist += (1 << i);
sol = min_dist;
}
}
cout << sol << '\n';
return 0;
}