//KM算法求解最小权,二分最优匹配
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<cmath>
using namespace std;
#define INF 99999999
#define maxn 105
char str[maxn][maxn];//存输入的字符数组
int lx[maxn],ly[maxn];//顶标
int xMatch[maxn],yMatch[maxn];//记录x与y的匹配值
bool visx[maxn],visy[maxn];
int w[maxn][maxn];//权值
int row,col;
int ans,slack,n;//slack为修改量
struct node
{
int x,y;
node(int xx,int yy)
{
x=xx;
y=yy;
}
};
bool findPath(int x)//寻找最优解
{
int temp;
visx[x]=true;
for(int y=1; y<=n; y++)
{
if(visy[y])continue;
temp=w[x][y]-lx[x]-ly[y];
if(temp==0)//说明是相等子图
{
visy[y]=true;
if(!yMatch[y]||findPath(yMatch[y]))
{
xMatch[x]=y;
yMatch[y]=x;
return true;
}
}
else if(slack>temp)//更新slack的值(最小)
slack=temp;
}
return false;
}
void km()
{
memset(xMatch,0,sizeof(xMatch));
memset(yMatch,0,sizeof(yMatch));
memset(ly,0,sizeof(lx));//初始化顶标
for(int i=0; i<=n; i++)
lx[i]=INF;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(lx[i]>w[i][j])
lx[i]=w[i][j];//
for(int x=1; x<=n; x++)
{
while(1)
{
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
slack=INF;
if(findPath(x))break;
for(int i=1; i<=n; i++)
{
if(visx[i]) lx[i]+=slack;//若求最大权匹配改为lx[i]-=slack;
if(visy[i]) ly[i]-=slack;//ly[i]+=slack;
}
}
}
}
int main()
{
while(scanf("%d%d",&row,&col))
{
if(row==0&&0==col)break;
ans=n=0;
vector<node> h,m;
for(int i=0; i<row; i++)
{
cin>>str[i];
for(int j=0; j<col; j++)
{
if(str[i][j]=='m')
{
m.push_back(node(i,j));//容器记录坐标(人的坐标)
++n;
}
if(str[i][j]=='H')
h.push_back(node(i,j));//记录房子的坐标
}
}
for(int i=0;i<m.size();i++)
for(int j=0;j<h.size();j++)
w[i+1][j+1]=abs(double(m[i].x-h[j].x))+abs(double(m[i].y-h[j].y));//计算距离。
km();
for(int y=1;y<=n;y++)
ans+=w[yMatch[y]][y];
cout<<ans<<endl;
}
return 0;
}