#include <stdio.h>
#include <iostream>
#include <string.h>
#include<cmath>
using namespace std;
const int N=300;
const int MAXE=200000;
const int inf=1<<30;
int head[N],ep;
int d[N],pre[N];
bool vis[N];
int q[MAXE];
struct Edge
{
int u,v,c,w,next;
}edge[MAXE];
void addedge(int u,int v,int w,int c)//u v 费用 容量
{
edge[ep].u=u;
edge[ep].v=v;
edge[ep].w=w;
edge[ep].c=c;
edge[ep].next=head[u];
head[u]=ep++;
edge[ep].v=u;
edge[ep].u=v;
edge[ep].w=-w;
edge[ep].c=0;
edge[ep].next=head[v];
head[v]=ep++;
}
int SPFA(int src,int des)
{
int l,r;
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
for(int i=0;i<=des;i++) d[i]=inf;
d[src]=0;
l=0;r=0;
q[r++]=src;
vis[src]=1;
while(l<r)
{
int u=q[l++];
vis[u]=0;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].c>0&&d[u]+edge[j].w<d[v])
{
d[v]=d[u]+edge[j].w;
pre[v]=j;
if(!vis[v])
{
vis[v]=1;
q[r++]=v;
}
}
}
}
if(d[des]==inf)
return 0;
return 1;
}
int MCMF(int src,int des)
{
int flow=0,ans=0;//flow是得到的最大流的值 ans得到的是最小的费用
while(SPFA(src,des))
{
ans+=d[des];
int u=des;
int mini=inf;
while(u!=src)
{
if(edge[pre[u]].c<mini)
mini=edge[pre[u]].c;
u=edge[pre[u]].u;
}
flow+=mini;
u=des;
while(u!=src)
{
edge[pre[u]].c-=mini;
edge[pre[u]^1].c+=mini;
u=edge[pre[u]].u;
}
}
return ans;
}
struct man
{
int x;
int y;
}M[111];
struct house
{
int x,y;
}H[111];
char str[111];
int main()
{
int n,m,mcnt,hcnt,i,j,src,des;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(!n&&!m) break;
ep=0;
memset(head,-1,sizeof(head));
mcnt=hcnt=0;
for(i=0;i<n;i++)
{
scanf("%s",str);
for(j=0;j<m;j++)
{
if(str[j]=='H')
{
hcnt++;
H[hcnt].x=i; H[hcnt].y=j;
}
else if(str[j]=='m')
{
mcnt++;
M[mcnt].x=i; M[mcnt].y=j;
}
}
}
for(i=1;i<=mcnt;i++)
{
for(j=1;j<=hcnt;j++)
{
int dis=abs(M[i].x-H[j].x)+abs(M[i].y-H[j].y);
addedge(i,mcnt+j,dis,1);
//addedge(mcnt+j,i,dis,1);
}
}
src=0;
des=mcnt+hcnt+1;
for(i=1;i<=mcnt;i++)
addedge(src,i,0,1);
for(j=1;j<=hcnt;j++)
addedge(mcnt+j,des,0,1);
int ans=MCMF(src,des);
printf("%d\n",ans);
}
return 0;
}
#include <stdio.h>
#include <iostream>
#include <string.h>
#include<math.h>
#define N 300
#define MAXE 200000
#define inf 1<<30
int head[N],ep; //ep记录的是加入的边数
int d[N],pre[N];
bool vis[N];
int q[MAXE];
struct Edge
{
int u,v,c,w,next;
}edge[MAXE];
void addedge(int u,int v,int w,int c) // 加边操作,u,v分别是起点和终点,w 记录 路径长度,c记录权值,此题中权值为1
{
edge[ep].u=u;
edge[ep].v=v;
edge[ep].w=w;
edge[ep].c=c;
edge[ep].next=head[u];
head[u]=ep++;
edge[ep].v=u;
edge[ep].u=v;
edge[ep].w=-w;
edge[ep].c=0;
edge[ep].next=head[v];
head[v]=ep++;
}
int SPFA(int src,int des) // SPFA 最短路算法,维护一个队列,scr源点,des汇点
{
int l,r;
memset(pre,-1,sizeof(pre)); // pre[] 数组记录前驱节点
memset(vis,0,sizeof(vis));
for(int i=0;i<=des;i++) d[i]=inf; // 初始化数据
d[src]=0; // 将源点出队列,并能够多次进入队列
l=0;r=0;
q[r++]=src;
vis[src]=1;
while(l<r)
{
int u=q[l++];
vis[u]=0;
for(int j=head[u];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].c>0&&d[u]+edge[j].w<d[v]) // 判断条件和spfa不同,加入了edge[j].c>0,保证了联通性
{
d[v]=d[u]+edge[j].w;
pre[v]=j;
if(!vis[v])
{
vis[v]=1;
q[r++]=v;
}
}
}
}
if(d[des]==inf)
return 0;
return 1;
}
int MCMF(int src,int des)
{
int flow=0,ans=0; //flow是得到的最大流的值 ans得到的是最小的费用
while(SPFA(src,des)) // SPFA 判断是否还有增广路径
{
ans+=d[des]; // 让ans + 上该次增广路径求得的最大能增广的所需的最小费用
int u=des;
int mini=inf;
while(u!=src)
{
if(edge[pre[u]].c<mini)
mini=edge[pre[u]].c;
u=edge[pre[u]].u;
}
flow+=mini; // 加上本次增广路径得到的,最小的流量(短板效应)
u=des; //利用回溯,改变流量
while(u!=src)
{
edge[pre[u]].c-=mini;
edge[pre[u]^1].c+=mini;
u=edge[pre[u]].u;
}
}
return ans; //返回费用
}
struct man // 定义一个M[]结构体,记录人的位置信息
{
int x;
int y;
}M[111];
struct house
{
int x,y;
}H[111]; // 定义一个H[]结构体,记录人的位置信息
char str[111];
int main()
{
int n,m,mcnt,hcnt,i,j,src,des; // hcnt,记录房子的个数,mcnt记录人的数目
while(scanf("%d%d",&n,&m)!=EOF)
{
if(!n&&!m) break;
ep=0;
memset(head,-1,sizeof(head)); //初始化ep,head【】,mcnt,hcnt;
mcnt=hcnt=0;
for(i=0;i<n;i++)
{
scanf("%s",str); //输入信息
for(j=0;j<m;j++)
{
if(str[j]=='H')
{
hcnt++;
H[hcnt].x=i; H[hcnt].y=j; // H[],数组记录房子的坐标
}
else if(str[j]=='m')
{
mcnt++;
M[mcnt].x=i; M[mcnt].y=j; // M[],数组记录人的坐标
}
}
}
for(i=1;i<=mcnt;i++)
{
for(j=1;j<=hcnt;j++)
{
int dis=fabs(M[i].x-H[j].x)+fabs(M[i].y-H[j].y); // dis求得 第i个人和第j个人房屋的距离。
addedge(i,mcnt+j,dis,1); //加入i,mcnt+j,这条边,dis 记录路径长度和加入权值1;
//addedge(mcnt+j,i,dis,1);
}
}
src=0;
des=mcnt+hcnt+1;
for(i=1;i<=mcnt;i++)
addedge(src,i,0,1); //表明源点和第i个人的距离为0,初始化每一个人和源点的距离;
for(j=1;j<=hcnt;j++)
addedge(mcnt+j,des,0,1); //表明汇点和第j座房屋的距离为0,初始化每一房屋和汇点的距离;
int ans=MCMF(src,des); // 求得ans记录从源点src到终点des的最小费用最大流
printf("%d\n",ans);
}
return 0;
}