费用流模板题
每个人到每个房子建立一条流量为1,费用为曼哈顿距离的边,然后跑一遍最小费用流即可;
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e4+7,maxm=2e5+7;
int h[maxn],e[maxm],ne[maxm],w[maxm],f[maxm],idx;
int dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool vis[maxn];
int n,m,k1,k2,s,t,max_flow,min_cost;
struct home{
int x,y;
}ho[maxn];
struct man{
int x,y;
}ma[maxn];
void add(int a,int b,int c,int d){
e[idx]=b,w[idx]=c,f[idx]=d,ne[idx]=h[a],h[a]=idx++;
}
inline int manhattan(man a,home b){
return abs(a.x-b.x)+abs(a.y-b.y);
}
bool spfa(int s,int t){
memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);pre[t]=-1;
queueq;q.push(s),vis[s]=1,dis[s]=0;
while(q.size()){
int x=q.front();q.pop();vis[x]=0;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(dis[j]>dis[x]+f[i]&&w[i]){
dis[j]=dis[x]+f[i];
flow[j]=min(flow[x],w[i]);
last[j]=i,pre[j]=x;
if(!vis[j])q.push(j),vis[j]=1;
}
}
}
return ~pre[t];
}
void solve(){
while(spfa(s,t)){
min_cost+=flow[t]*dis[t];
max_flow+=flow[t];
int p=t;
while(p!=s){
w[last[p]]-=flow[t];
w[last[p]^1]+=flow[t];
p=pre[p];
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)&&(n||m)){
memset(h,-1,sizeof h),idx=0;char c;k1=k2=0;min_cost=max_flow=0;
for(int i=1;i<=n;i++){
char c[maxn];scanf("%s",c+1);
for(int j=1;j<=m;j++){
if(c[j]=='H')ho[++k1]={i,j};
else if(c[j]=='m')ma[++k2]={i,j};
}
}
s=0,t=k1+k2+2;
for(int i=1;i<=k2;i++)
for(int j=1;j<=k1;j++){
int x=manhattan(ma[i],ho[j]);
add(i,k2+j,1,x),add(k2+j,i,0,-x);
}
for(int i=1;i<=k2;i++)add(s,i,1,0),add(i,s,0,0);
for(int i=1;i<=k1;i++)add(k2+i,t,1,0),add(t,k2+i,1,0);
solve();
printf("%d\n",min_cost);
}
return 0;
}