//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;
}