#include <iostream>
#include <cstdint>
#include <iterator>
#include <algorithm>
#include <array>
#include <queue>
#include <numeric>
template<typename T>
class NumIter
{
public:
using iterator_category = std::random_access_iterator_tag;
using value_type = T;
using difference_type = std::int64_t;
using pointer = T;
using reference = T;
NumIter(const T x)
: value(x)
{
}
T operator*() const
{
return value;
}
NumIter& operator++()
{
++value;
return *this;
}
NumIter operator++(int)
{
const NumIter old{value};
++value;
return old;
}
NumIter& operator--()
{
--value;
return *this;
}
NumIter operator--(int)
{
const NumIter old{value};
--value;
return old;
}
NumIter& operator+=(const std::int64_t n)
{
value += n;
return *this;
}
auto operator-(const NumIter& other) const
{
return static_cast<difference_type>(value) -
static_cast<difference_type>(other.value);
}
bool operator==(const NumIter& other) const
{
return value == other.value;
}
private:
T value = {};
};
static int R;
static int C;
struct Room
{
bool operator==(const Room& other) const
{
return x == other.x && y == other.y;
}
bool valid() const
{
return 0 <= x && x < R && 0 <= y && y < C;
}
std::array<Room, 4> neighbours() const
{
const std::array<Room, 4> res = {
{{x, y - 1}, {x, y + 1}, {x - 1, y}, {x + 1, y}}};
return res;
}
int x, y;
};
bool DFS(const Room src, const Room dest, const int K, std::vector<std::vector<char>>& visited,
const std::vector<std::string>& mat, const std::vector<std::vector<int>>& dist)
{
visited[src.x][src.y] = true;
if(src == dest)
{
return true;
}
for(const Room& neigh : src.neighbours())
{
if(!neigh.valid() || visited[neigh.x][neigh.y] ||
mat[neigh.x][neigh.y] == '*' || mat[neigh.x][neigh.y] == 'D' ||
dist[neigh.x][neigh.y] < K)
{
continue;
}
if(DFS(neigh, dest, K, visited, mat, dist) == true)
{
return true;
}
}
return false;
}
bool check_for_k(const Room& src, const Room& dest, const int K,
const std::vector<std::vector<int>>& dist,
const std::vector<std::string>& mat)
{
auto visited = std::vector<std::vector<char>>(R, std::vector<char>(C, false));
const bool res = dist[src.x][src.y] >= K && dist[dest.x][dest.y] >= K &&
DFS(src, dest, K, visited, mat, dist);
return !res;
}
int main()
{
std::freopen("barbar.in", "r", stdin);
std::freopen("barbar.out", "w", stdout);
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> R >> C;
std::cin.ignore();
std::vector<std::string> mat(R);
std::queue<Room> drag_q;
Room src;
Room dest;
std::vector<std::vector<int>> dist(R, std::vector<int>(C));
std::vector<std::vector<char>> visited(R, std::vector<char>(C, false));
for(int i = 0; i < R; ++i)
{
std::getline(std::cin, mat[i]);
for(int j = 0; j < C; ++j)
{
if(mat[i][j] == 'I')
{
src = {i, j};
}
if(mat[i][j] == 'O')
{
dest = {i, j};
}
if(mat[i][j] == 'D')
{
drag_q.push(Room{i, j});
dist[i][j] = 0;
visited[i][j] = true;
}
}
}
while(!drag_q.empty())
{
const auto c_room = drag_q.front();
drag_q.pop();
for(const Room& r : c_room.neighbours())
{
if(!r.valid() || visited[r.x][r.y] || mat[r.x][r.y] == '*')
{
continue;
}
drag_q.push(r);
dist[r.x][r.y] = 1 + dist[c_room.x][c_room.y];
visited[r.x][r.y] = true;
}
}
int res = *std::lower_bound(NumIter<int>{1}, NumIter<int>{R * C}, true,
[&](const int i1, const int i2)
{
return check_for_k(src, dest, i1, dist, mat) < i2;
});
if(res == 1)
{
puts("-1");
return 0;
}
--res;
std::cout << res << '\n';
}