//最小权匹配(KM算法) #include<iostream> #include<cstring> #include<vector> using namespace std; const int MAX = 105; const int INF = 2147483647; char G[MAX][MAX]; int lx[MAX],ly[MAX],xMatch[MAX],yMatch[MAX]; bool vis_x[MAX],vis_y[MAX]; int W[MAX][MAX]; int slack,ans,N,R,C; struct coord { int x,y; coord(int xx,int yy) { x = xx; y = yy; } }; bool findPath(int x) { int temp; vis_x[x] = true; for(int y = 1;y <= N;++y) { if(vis_y[y]) continue; temp = W[x][y] - lx[x] - ly[y];//若求最大权匹配,则改为lx[x]+ly[y]-W[x][y] if(temp == 0) { vis_y[y] = true; if(!yMatch[y] || findPath(yMatch[y])) { xMatch[x] = y;//记录匹配情况,这里的xMatch可以省略 yMatch[y] = x; return true; } } else if(slack > temp) slack = temp;//更新slack值 } return false; } void KM() { memset(xMatch,0,sizeof(xMatch)); memset(yMatch,0,sizeof(yMatch)); memset(ly,0,sizeof(ly)); for(int i = 1;i <= N;++i) lx[i] = INF; for(int x = 1;x <= N;++x) for(int y = 1;y <= N;++y) if(lx[x] > W[x][y]) lx[x] = W[x][y]; for(int x = 1;x <= N;++x) { while(1) { memset(vis_x,0,sizeof(vis_x)); memset(vis_y,0,sizeof(vis_y)); slack = INF; if(findPath(x)) break; for(int i = 1;i <= N;++i) { if(vis_x[i]) lx[i] += slack;//若求最大权匹配改lx[i]-=slack; if(vis_y[i]) ly[i] -= slack;//ly[i]+=slack; } } } } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d",&R,&C) && R) { ans = N = 0; vector<coord> H,m; for(int i = 0;i < R;++i)//构图 { scanf("%s",G[i]); for(int j = 0;j < C;++j) { if(G[i][j] == 'm') { m.push_back(coord(i,j)); ++N; } if(G[i][j] == 'H') H.push_back(coord(i,j)); } } for(int i = 0;i < m.size();++i) for(int j = 0;j < H.size();++j) W[i+1][j+1] = abs(m[i].x - H[j].x) + abs(m[i].y - H[j].y);//算距离 KM(); for(int y = 1;y <= N;++y) ans += W[yMatch[y]][y]; printf("%d/n",ans); } return 0; }