题意:地图中有n个小人和n个小房子,每个小人和每个房子之间都有一定的距离,现在要使每个房子都住进一个小人,求这n个小人走进各自房子的距离之和的最小值。
难度:1
题解:二分图最大权匹配。用最小费用最大流求解。设立一个附加源和附加汇,附加源和每个小人连一条流量为1,费用为0的边,每个房子向附加汇连一条流量为1费用为0的边,每个小人向每个房子连一条流量不为0,费用为彼此距离的边,求最小费用最大流。
难度:1
题解:二分图最大权匹配。用最小费用最大流求解。设立一个附加源和附加汇,附加源和每个小人连一条流量为1,费用为0的边,每个房子向附加汇连一条流量为1费用为0的边,每个小人向每个房子连一条流量不为0,费用为彼此距离的边,求最小费用最大流。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define inf (1<<29)
const int maxn = 222 , maxm = 55555;
struct Edge {
int u,v,f,c,next;
}edge[maxm];
int E,head[maxn];
void init() {
E=0;memset(head,-1,sizeof(head));
}
void _add(int u,int v,int f,int c) {
edge[E].u=u;edge[E].v=v;edge[E].f=f;edge[E].c=c;edge[E].next=head[u];head[u]=E++;
}
void addedge(int u,int v,int f,int c) {
_add(u,v,f,c); _add(v,u,0,-c);
}
int n , maxf , minc;
int dist[maxn] , p[maxn] , sta[maxn];
bool vis[maxn];
bool spfa(int s,int t) {
int u , v ,f , c;
for(int i=0;i<n;i++) dist[i] = inf , vis[i] = 0 , p[i] = -1;
int top = 0;
sta[++top] = s;
dist[s] = 0;
while(top) {
u=sta[top--];
vis[u] = 0;
for(int i=head[u];i!=-1;i=edge[i].next) {
v = edge[i].v;
f = edge[i].f;
c = edge[i].c;
if(f && dist[v] > dist[u] + c) {
p[v] = i;
dist[v] = dist[u] + c;
if(!vis[v]) {
vis[v] = 1;
sta[++top] = v;
}
}
}
}
return dist[t] != inf;
}
void mcmf(int s,int t) {
maxf = minc = 0;
while(spfa(s,t)) {
//printf("tmp of spfa : %d\n",dist[t]);
int minf = inf;
for(int i=p[t];i!=-1;i=p[edge[i].u])
if(edge[i].f < minf) minf = edge[i].f;
maxf += minf;
minc += minf * dist[t];
for(int i=p[t];i!=-1;i=p[edge[i].u]) {
edge[i].f -= minf;
edge[i^1].f += minf;
}
}
}
char map[maxn][maxn];
int N , M , n1 , n2;
int x[maxn] , y[maxn];
int xx[maxn] , yy[maxn];
int dis(int i,int j) {
return abs(x[i]-xx[j]) + abs(y[i]-yy[j]);
}
int main() {
while(~scanf("%d%d",&N,&M) && N+M) {
init();
for(int i=0;i<N;i++) scanf("%s",map[i]);
n1 = n2 = 0;
for(int i=0;i<N;i++)
for(int j=0;j<M;j++) {
if(map[i][j] == 'H') {
x[n1] = i;
y[n1] = j;
n1 ++;
}
if(map[i][j] == 'm') {
xx[n2] = i;
yy[n2] = j;
n2 ++;
}
}
//printf("n1 == %d\n n2 == %d\n",n1,n2);
int s = n1<<1 , t = n1<<1|1;
n = t + 1;
for(int i=0;i<n1;i++)
for(int j=0;j<n2;j++)
addedge(i,j+n1,1,dis(i,j));
for(int i=0;i<n1;i++) {
addedge(s,i,1,0);
addedge(i+n1,t,1,0);
}
mcmf(s,t);
printf("%d\n",minc);
}
return 0;
}