#include <fstream>
#include <iostream>
#include <queue>
#include <vector>
const int MAX_N = 1005;
const int dx[] = {0, 1, 0, -1};
const int dy[] = {-1, 0, 1, 0};
class Matrix {
private:
std::vector< std::vector<int> > data;
public:
Matrix() {}
Matrix(int n, int m, int val=0) {
data.assign(n, std::vector<int>(m, val));
}
int n() const {
return data.size();
}
int m() const {
return data[0].size();
}
bool in(int x, int y) const {
return 0 <= x && x < n() && 0 <= y && y < m();
}
int get(int x, int y) const {
return data[x][y];
}
void set(int x, int y, int val) {
data[x][y] = val;
}
std::vector< std::pair<int, int> > Neighbours(int x, int y) const {
std::vector< std::pair<int, int> > ret;
for (int d = 0; d < 4; ++ d) {
std::pair<int, int> neighbour = {x + dx[d], y + dy[d]};
if (in(neighbour.first, neighbour.second)) {
ret.push_back(neighbour);
}
}
return ret;
}
};
bool CanTravel(int dist, std::pair<int, int> start, std::pair<int, int> stop, const Matrix &dragon_dists, const std::vector< std::vector<bool> > &walls) {
std::queue< std::pair<int, int> > q;
std::vector< std::vector<bool> > visited(dragon_dists.n(), std::vector<bool>(dragon_dists.m(), false));
q.push(start);
visited[start.first][start.second] = true;
while (!q.empty()) {
auto pos = q.front();
q.pop();
for (auto new_pos : dragon_dists.Neighbours(pos.first, pos.second)) {
if (!visited[new_pos.first][new_pos.second] && !walls[new_pos.first][new_pos.second] && dragon_dists.get(new_pos.first, new_pos.second) >= dist) {
if (new_pos == stop) {
return true;
}
visited[new_pos.first][new_pos.second] = true;
q.push(new_pos);
}
}
}
return false;
}
Matrix bfs(const std::vector< std::pair<int, int> > &dragons, const std::vector< std::vector<bool> > &walls) {
std::queue< std::pair<int, int> > q;
Matrix dist(walls.size(), walls[0].size(), 1000000000);
for (auto dragon: dragons) {
dist.set(dragon.first, dragon.second, 0);
q.push(dragon);
}
while (!q.empty()) {
auto pos = q.front();
q.pop();
for (auto new_pos : dist.Neighbours(pos.first, pos.second)) {
if (dist.get(new_pos.first, new_pos.second) == 1000000000 && !walls[new_pos.first][new_pos.second]) {
dist.set(new_pos.first, new_pos.second, dist.get(pos.first, pos.second) + 1);
q.push(new_pos);
}
}
}
return dist;
}
int main()
{
std::ifstream cin("barbar.in");
std::ofstream cout("barbar.out");
int n, m;
cin >> n >> m;
std::pair<int, int> start, stop;
std::vector< std::pair<int, int> > dragons;
std::vector< std::vector<bool> > walls(n, std::vector<bool>(m, false));
for (int i = 0; i < n; ++ i) {
std::string line;
cin >> line;
for (int j = 0; j < m; ++ j) {
if (line[j] == '.') {
continue;
}
if (line[j] == 'D') {
dragons.push_back({i, j});
continue;
}
if (line[j] == '*') {
walls[i][j] = true;
continue;
}
if (line[j] == 'I') {
start = {i, j};
} else {
stop = {i, j};
}
}
}
auto dragon_dists = bfs(dragons, walls);
int left = 0, right = n * m, best = -1;
while (left <= right) {
int middle = (left + right) / 2;
if (CanTravel(middle, start, stop, dragon_dists, walls)) {
best = middle;
left = middle + 1;
} else {
right = middle - 1;
}
}
cout << best << "\n";
return 0;
}