题意
传送门 POJ 2195
题解
B F S BFS BFS 求每个人到每个房子的最短距离;每个人向每个房子连一条容量为 1 1 1 费用为最短距离的边;最小费用流即答案。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define abs(x) ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define delta 0.85
#define eps 1e-10
#define PI 3.14159265358979323846
using namespace std;
#define MAX_V 210
struct edge{
int to, cap, cost, rev;
edge(int to, int cap, int cost, int rev):to(to), cap(cap), cost(cost), rev(rev){}
};
int V;
vector<edge> G[MAX_V];
int h[MAX_V], dist[MAX_V];
int prevv[MAX_V], preve[MAX_V];
void add_edge(int from, int to, int cap, int cost){
G[from].push_back(edge(to, cap, cost, G[to].size()));
G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));
}
int min_cost_flow(int s, int t, int f){
int res = 0;
memset(h, 0, sizeof(h));
while(f > 0){
// Dijkstra
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;
memset(dist, 0x3f, sizeof(dist));
dist[s] = 0;
que.push(pair<int, int>(0, s));
while(!que.empty()){
pair<int, int> p = que.top(); que.pop();
int v = p.second;
if(dist[v] < p.first) continue;
for(int i = 0; i < G[v].size(); i++){
edge &e = G[v][i];
int d2 = dist[v] + e.cost + h[v] - h[e.to];
if(e.cap > 0 && d2 < dist[e.to]){
dist[e.to] = d2;
prevv[e.to] = v;
preve[e.to] = i;
que.push(pair<int, int>(dist[e.to], e.to));
}
}
}
if(dist[t] == INF){
return -1;
}
for(int v = 0; v < V; v++) h[v] += dist[v];
int d = f;
for(int v = t; v != s; v = prevv[v]){
d = min(d, G[prevv[v]][preve[v]].cap);
}
f -= d;
res += d * h[t];
for(int v = t; v != s; v = prevv[v]){
edge &e = G[prevv[v]][preve[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}
void clear_graph(){
for(int v = 0; v < V; v++) G[v].clear();
}
#define MAX_N 105
const int dx[4] = {0, 0, -1, 1};
const int dy[4] = {-1, 1, 0, 0};
int N, M;
char mp[MAX_N][MAX_N];
int dis[MAX_N][MAX_N];
vector<int> pX, pY, hX, hY;
void bfs(int x, int y){
memset(dis, 0x3f, sizeof(dis));
dis[x][y] = 0;
queue<int> qx, qy;
qx.push(x); qy.push(y);
while(!qx.empty()){
int x = qx.front(); qx.pop();
int y = qy.front(); qy.pop();
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx >= 0 && nx < N && ny >= 0 && ny < M && dis[nx][ny] == INF){
dis[nx][ny] = dis[x][y] + 1;
qx.push(nx); qy.push(ny);
}
}
}
}
void solve(){
pX.clear(); pY.clear(); hX.clear(); hY.clear();
for(int i = 0; i < N; i++){
for(int j = 0; j < M; j++){
if(mp[i][j] == 'H'){
hX.push_back(i);
hY.push_back(j);
}
else if(mp[i][j] == 'm'){
pX.push_back(i);
pY.push_back(j);
}
}
}
int H = hX.size();
int s = H + H, t = s + 1;
V = t + 1;
clear_graph();
// 每个人向每个房子连一条费用为最短距离的边
for(int i = 0; i < H; i++){
bfs(hX[i], hY[i]);
for(int j = 0; j < H; j++){
add_edge(i, H + j, 1, dis[pX[j]][pY[j]]);
}
}
for(int i = 0; i < H; i++){
add_edge(s, i, 1, 0);
}
for(int i = H; i < s; i++){
add_edge(i, t, 1, 0);
}
printf("%d\n", min_cost_flow(s, t, H));
}
int main(){
while(~scanf("%d%d", &N, &M) && (N | M)){
for(int i = 0; i < N; i++) scanf(" %s", mp + i);
solve();
}
return 0;
}