把每个点移动到对应位置的总费用最小。建图后费用流。继续水水练练手~
#include<iostream>
#include<queue>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int MAXN=20005, MAXE=4000000;
int e[MAXE][4];int head[MAXN];int nume;
int n,m;int N,M;
void inline adde(int i,int j,int c,int w)
{
e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
e[nume][2]=c;e[nume++][3]=w;
e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
e[nume][2]=0;e[nume++][3]=-w;
}
struct point
{
int x,y;
int id;
};
int inline getdis(point a,point b)
{
return abs(a.x-b.x)+abs(a.y-b.y);
}
vector<point>man,house;
void build()
{
N=man.size();M=house.size();
for(int i=0;i<N;i++)
{
adde(0,i+1,1,0);
for(int j=0;j<M;j++)
adde(i+1,j+1+N,1,getdis(man[i],house[j]));
}
for(int i=0;i<M;i++)
adde(i+N+1,N+M+1,1,0);
}
int inq[MAXN];int prv[MAXN];int pre[MAXN];
int d[MAXN];
bool spfa(int & sum)
{
for(int i=0;i<=N+M+1;i++)
{
d[i]=inf;
pre[i]=prv[i]=inq[i]=0;
}
queue<int>q;
q.push(0);
inq[0]=1;
d[0]=0;
while(!q.empty())
{
int cur=q.front();
q.pop();
inq[cur]=0;
for(int j=head[cur];j!=-1;j=e[j][1])
{
int to=e[j][0];
if(d[to]>d[cur]+e[j][3]&&e[j][2]>0)
{
d[to]=d[cur]+e[j][3];
pre[to]=j;
prv[to]=cur;
if(!inq[to])
{
q.push(to);
inq[to]=1;
}
}
}
}
int minf=inf;
if(d[N+M+1]==inf)return 0;
int cur=N+M+1;
while(cur!=0)
{
minf=min(minf,e[pre[cur]][2]);
cur=prv[cur];
}
cur=N+M+1;
while(cur!=0)
{
e[pre[cur]][2]-=minf;
e[pre[cur]^1][2]+=minf;
cur=prv[cur];
}
sum+=d[N+M+1]*minf;
return 1;
}
int mincost()
{
int sum=0;
while(spfa(sum));
return sum;
}
void init()
{
for(int i=0;i<MAXN-1;i++)
{
head[i]=-1;
}
nume=0;
man.clear();
house.clear();
}
int main()
{
while(~scanf("%d%d",&n,&m)&&(n||m))
{
init();
char t; point p;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>t;
if(t=='m')
{
p.x=i;p.y=j;
p.id=1;
man.push_back(p);
}
else if(t=='H')
{
p.x=i;p.y=j;
p.id=2;
house.push_back(p);
}
}
build();
int ans=mincost();
printf("%d\n",ans);
}
return 0;
}