题目传送门
1 /*
2 最小费用流:KM算法是求最大流,只要w = -w就可以了,很经典的方法
3 */
4 #include <cstdio>
5 #include <cmath>
6 #include <algorithm>
7 #include <cstring>
8 using namespace std;
9
10 const int MAXN = 1e2 + 10;
11 const int INF = 0x3f3f3f3f;
12 int x[MAXN], y[MAXN];
13 int w[MAXN][MAXN];
14 int visx[MAXN], visy[MAXN];
15 int ly[MAXN];
16 int mx[MAXN], my[MAXN];
17 int hx[MAXN], hy[MAXN];
18 char maze[MAXN][MAXN];
19 int n, m, un, vn, d;
20
21 bool DFS(int u) {
22 visx[u] = true;
23 for (int i=1; i<=un; ++i) {
24 if (!visy[i] && x[u] + y[i] == w[u][i]) {
25 visy[i] = true;
26 if (ly[i] == -1 || DFS (ly[i])) {
27 ly[i] = u; return true;
28 }
29 }
30 else if (x[u] + y[i] > w[u][i]) d = min (d, x[u] + y[i] - w[u][i]);
31 }
32 return false;
33 }
34
35 int KM(void) {
36 for (int i=1; i<=un; ++i) {
37 x[i] = -INF;
38 for (int j=1; j<=vn; ++j) {
39 x[i] = max (x[i], w[i][j]);
40 }
41 }
42
43 memset (ly, -1, sizeof (ly));
44 memset (y, 0, sizeof (y));
45 for (int i=1; i<=un; ++i) {
46 while (true) {
47 memset (visx, false, sizeof (visx));
48 memset (visy, false, sizeof (visy));
49 d = INF;
50 if (DFS (i)) break;
51 for (int i=1; i<=un; ++i) {
52 if (visx[i]) x[i] -= d;
53 }
54 for (int j=1; j<=vn; ++j) {
55 if (visy[j]) y[j] += d;
56 }
57 }
58 }
59
60 int res = 0;
61 for (int i=1; i<=un; ++i) {
62 res += x[i] + y[i];
63 }
64
65 return res;
66 }
67
68 int main(void) { //HDOJ 1533 Going Home
69 //freopen ("HDOJ_1533.in", "r", stdin);
70
71 while (scanf ("%d%d", &n, &m) == 2) {
72 if (!n && !m) break;
73 for (int i=1; i<=n; ++i) {
74 scanf ("%s", maze[i] + 1);
75 }
76 un = vn = 0;
77 for (int i=1; i<=n; ++i) {
78 for (int j=1; j<=m; ++j) {
79 if (maze[i][j] == 'm') mx[++un] = i, my[un] = j;
80 else if (maze[i][j] == 'H') hx[++vn] = i, hy[vn] = j;
81 }
82 }
83 for (int i=1; i<=un; ++i) {
84 for (int j=1; j<=vn; ++j) {
85 w[i][j] = -(abs (mx[i] - hx[j]) + abs (my[i] - hy[j]));
86 }
87 }
88 printf ("%d
", -KM ());
89 }
90
91 return 0;
92 }