1 /*
2 题意:给出一个n*m的图,H表示房子,m表示人的初始位置,.表示空位置,每个人从他的位置(x1,y1)走到H的位置(x2,y2)需要花费
3 sum = abs(x1-x2) + abs(y1-y2),每个人都必须走进一间房子,且每间房子都只能容纳一个人,问最少花费多少使得所有的人都走
4 进房间里
5
6 题解:权最大完美匹配(KM算法)
7 以n个人和n个房间建图,边权为人i走到房间j所需要的花费,然后求最大完美匹配即可。
8 */
9 #include <cstdio>
10 #include <cstring>
11
12 #define MAXV 105
13
14 const int INF = (1<<31)-1;
15
16 struct node
17 {
18 int x,y;
19 }man[MAXV],home[MAXV]; // 记录所有人和房间的位置
20 int mnum,hnum; // 人和房间的数量
21 int n,m;
22
23 int w[MAXV][MAXV]; // 记录人走到所有房间的权值
24
25 int abs(int t)
26 {
27 return t > 0 ? t : -t;
28 }
29
30 int lx[MAXV],ly[MAXV],match[MAXV];
31 int slack[MAXV];
32 bool visx[MAXV],visy[MAXV];
33
34 bool find(int u)
35 {
36 visx[u] = true;
37 for(int i=0; i<m; i++)
38 {
39 if (visy[i])
40 continue;
41 if (lx[u] + ly[i] == w[u][i])
42 {
43 visy[i] = true;
44 if (match[i] == -1 || find(match[i]))
45 {
46 match[i] = u;
47 return true;
48 }
49 }
50 else if (slack[i] > lx[u] + ly[i] - w[u][i])
51 slack[i] = lx[u] + ly[i] - w[u][i];
52 }
53 return false;
54 }
55
56 int KM()
57 {
58 memset(ly,0,sizeof(ly));
59 for(int i=0; i<n; i++)
60 {
61 lx[i] = -INF;
62 for(int j=0; j<m; j++)
63 if (lx[i] < w[i][j])
64 lx[i] = w[i][j];
65 }
66
67 memset(match, -1, sizeof(match));
68 for(int i=0; i<n ;i++)
69 {
70 for(int j=0; j<m; j++)
71 slack[j] = INF;
72 while (true)
73 {
74 memset(visx,false,sizeof(visx));
75 memset(visy,false,sizeof(visy));
76 if (find(i))
77 break;
78
79 int d = INF;
80 for(int j=0; j<m; j++)
81 if (!visy[j] && d > slack[j])
82 d = slack[j];
83 for(int j=0; j<n; j++)
84 if (visx[j])
85 lx[j] -= d;
86 for(int j=0; j<m; j++)
87 {
88 if (visy[j])
89 ly[j] += d;
90 else
91 slack[j] -= d;
92 }
93 }
94 }
95
96 int sum = 0;
97 for(int i=0; i<n; i++)
98 if (match[i] != -1)
99 sum += w[match[i]][i];
100 return sum;
101 }
102
103 int main(void)
104 {
105 while (~scanf("%d%d",&n,&m), n || m)
106 {
107 mnum = hnum = 0;
108 char s[105];
109 for(int i=0; i<n; i++)
110 {
111 scanf("%s",s);
112 for(int j=0; j<m; j++)
113 {
114 if ('H' == s[j])
115 {
116 home[hnum].x = i;
117 home[hnum].y = j;
118 hnum ++;
119 }
120 else if ('m' == s[j])
121 {
122 man[mnum].x = i;
123 man[mnum].y = j;
124 mnum ++;
125 }
126 }
127 }
128
129 for(int i=0; i<mnum; i++)
130 for(int j=0; j<hnum; j++)
131 {
132 w[i][j] = -abs(man[i].x - home[j].x) - abs(man[i].y - home[j].y); // 初始为负值,这样最后取反得到最小值
133 }
134 n = mnum;
135 m = hnum;
136 printf("%d\n",-KM());
137 }
138 return 0;
139 }