#include <iostream>
#include <fstream>
#include <queue>
#include <vector>
#include <climits>
using namespace std;
const int DIRS = 4;
const int dx[DIRS] = {-1, 1, 0, 0};
const int dy[DIRS] = {0, 0, -1, 1};
struct Cell {
int x, y;
};
bool isValid(int x, int y, int R, int C, const vector<string>& grid) {
return x >= 0 && x < R && y >= 0 && y < C && grid[x][y] != '*';
}
bool canReach(int minDist, const vector<vector<int>>& dist, Cell start, Cell exit, int R, int C, const vector<string>& grid) {
queue<Cell> q;
vector<vector<bool>> visited(R, vector<bool>(C, false));
q.push(start);
visited[start.x][start.y] = true;
while (!q.empty()) {
Cell current = q.front();
q.pop();
if (current.x == exit.x && current.y == exit.y) {
return true;
}
for (int d = 0; d < DIRS; ++d) {
int nx = current.x + dx[d];
int ny = current.y + dy[d];
if (isValid(nx, ny, R, C, grid) && !visited[nx][ny] && dist[nx][ny] >= minDist) {
visited[nx][ny] = true;
q.push({nx, ny});
}
}
}
return false;
}
int main() {
ifstream fin("barbar.in");
ofstream fout("barbar.out");
int R, C;
fin >> R >> C;
vector<string> grid(R);
for (int i = 0; i < R; ++i) {
fin >> grid[i];
}
Cell start, exit;
queue<Cell> dragons;
vector<vector<int>> dist(R, vector<int>(C, INT_MAX));
vector<vector<bool>> visited(R, vector<bool>(C, false));
for (int i = 0; i < R; ++i) {
for (int j = 0; j < C; ++j) {
if (grid[i][j] == 'I') {
start = {i, j};
} else if (grid[i][j] == 'O') {
exit = {i, j};
} else if (grid[i][j] == 'D') {
dragons.push({i, j});
dist[i][j] = 0;
visited[i][j] = true;
}
}
}
while (!dragons.empty()) {
Cell current = dragons.front();
dragons.pop();
for (int d = 0; d < DIRS; ++d) {
int nx = current.x + dx[d];
int ny = current.y + dy[d];
if (isValid(nx, ny, R, C, grid) && !visited[nx][ny] && dist[nx][ny] > dist[current.x][current.y] + 1) {
dist[nx][ny] = dist[current.x][current.y] + 1;
visited[nx][ny] = true;
dragons.push({nx, ny});
}
}
}
int left = 0, right = R * C;
int bestDist = -1;
while (left <= right) {
int mid = (left + right) / 2;
if (canReach(mid, dist, start, exit, R, C, grid)) {
bestDist = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
fout << bestDist << endl;
fin.close();
fout.close();
return 0;
}