#include <stdio.h>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int START=2,FINISH=3,WALL=-1,EMPTY=0,DRAGON=1,INF=10000000;
int R,C,a[1004][1004],dist[1004][1004],GDist[1004][1004],viz[1004][1004];
char buff[1005];
class Point{
public:int x,y,d;
public:Point(int xx,int yy,int dd):x(xx),y(yy),d(dd){}
public:bool operator<(Point other)const{return d<other.d;}
public:bool operator>(Point other)const{return d>other.d;}
};
queue<Point> dragons;
bool isValid(int x,int y){
return (x>=0 && x<R &&y>=0 && y<C && a[x][y]!=WALL && a[x][y]!=DRAGON);
}
Point startPoint=Point(0,0,0),endPoint=Point(0,0,0);
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
bool isRoadDoable(int d){
memset(viz,0,sizeof(viz));
viz[startPoint.x][startPoint.y]=1;
queue<Point> q;q.push(startPoint);
while(!q.empty()){
Point u = q.front();q.pop();
for(int i=0;i<4;i++){
if(isValid(u.x+dx[i],u.y+dy[i]) && !viz[u.x+dx[i]][u.y+dy[i]] && dist[u.x+dx[i]][u.y+dy[i]]>=d){
viz[u.x+dx[i]][u.y+dy[i]]=true;
q.push(Point(u.x+dx[i],u.y+dy[i],0));
}
}
}
return viz[endPoint.x][endPoint.y];
}
int main(){
freopen("barbar.in","r",stdin);
freopen("barbar.out","w",stdout);
scanf("%d %d",&R,&C);
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
dist[i][j]=INF;
for(int i=0;i<R;i++){
scanf("%s",buff);
for(int j=0;j<C;j++){
if(buff[j]=='.') a[i][j]=EMPTY;
if(buff[j]=='*') a[i][j]=WALL;
if(buff[j]=='D') {a[i][j]=DRAGON;dist[i][j]=0;dragons.push(Point(i,j,0));}
if(buff[j]=='I') {a[i][j]=START;startPoint=Point(i,j,0);}
if(buff[j]=='O') {a[i][j]=FINISH;endPoint=Point(i,j,0);}
}
}
while(!dragons.empty()){
Point dr=dragons.front();dragons.pop();
for(int i=0;i<4;i++){
if(isValid(dr.x+dx[i],dr.y+dy[i]) && dist[dr.x+dx[i]][dr.y+dy[i]]==INF){
dist[dr.x+dx[i]][dr.y+dy[i]]=dist[dr.x][dr.y]+1;
dragons.push(Point(dr.x+dx[i],dr.y+dy[i],0));
}
}
}
priority_queue<Point, vector<Point>, less<Point> > pq;
/*
startPoint.d=dist[startPoint.x][startPoint.y];
GDist[startPoint.x][startPoint.y]=dist[startPoint.x][startPoint.y];
viz[startPoint.x][startPoint.y]=1;
pq.push(startPoint);
while(!pq.empty()){
Point u=pq.top();pq.pop();
for(int i=0;i<4;i++){
if(isValid(u.x+dx[i],u.y+dy[i]) && !viz[u.x+dx[i]][u.y+dy[i]]){
viz[u.x+dx[i]][u.y+dy[i]]=true;
GDist[u.x+dx[i]][u.y+dy[i]]=min(dist[u.x+dx[i]][u.y+dy[i]],u.d);
pq.push(Point(u.x+dx[i],u.y+dy[i],GDist[u.x+dx[i]][u.y+dy[i]]));
}
}
}
if(viz[endPoint.x][endPoint.y])
printf("%d",GDist[endPoint.x][endPoint.y]);
else
printf("-1");
*/
int maxD=-1;
if(dist[endPoint.x][endPoint.y]!=INF){
int st=0,dr=R*C;
int mij;
while(st<=dr){
mij=(st+dr)>>1;
if(isRoadDoable(mij)){
maxD=mij;
st=mij+1;
}
else{
dr=mij-1;
}
}
}
printf("%d",maxD);
return 0;
}