题意:
一个$N$行$M$列的矩阵,其中$"."$代表空地,$"H"$代表房子,$"m"$代表人,其中有$n$个房子和$n$个人。现在要求每个人进入其中的一间房子,且每人每走一步需要支付$1$美元。求最小需要花费多少美元能让所有人都进入到房子中(每个人只能进入一间房子,每个房子只能容纳一个人)。
思路:
费用流,人和源点建流量$1$费用$0$的边;人和房子建流量$1$,费用为哈夫曼距离的边;房子和汇点建流量$1$费用$0$的边。
代码:
1 //#include<bits/stdc++.h>
2 #include <set>
3 #include <map>
4 #include <stack>
5 #include <cmath>
6 #include <queue>
7 #include <cstdio>
8 #include <string>
9 #include <vector>
10 #include <cstring>
11 #include <iostream>
12 #include <algorithm>
13
14 #define ll long long
15 #define pll pair<ll,ll>
16 #define pii pair<int,int>
17 #define bug printf("*********
")
18 #define FIN freopen("input.txt","r",stdin);
19 #define FON freopen("output.txt","w+",stdout);
20 #define IO ios::sync_with_stdio(false),cin.tie(0)
21 #define ls root<<1
22 #define rs root<<1|1
23 #define Q(a) cout<<a<<endl
24
25 using namespace std;
26 const int inf = 0x3f3f3f3f;
27 const ll Inf = 1e18 + 7;
28 const int maxn = 1e4 + 5;
29 const int mod = 1e9 + 7;
30
31 ll gcd(ll a, ll b)
32 {
33 return b ? gcd(b, a % b) : a;
34 }
35
36 ll lcm(ll a, ll b)
37 {
38 return a / gcd(a, b) * b;
39 }
40
41 ll read()
42 {
43 ll p = 0, sum = 0;
44 char ch;
45 ch = getchar();
46 while (1)
47 {
48 if (ch == '-' || (ch >= '0' && ch <= '9'))
49 break;
50 ch = getchar();
51 }
52
53 if (ch == '-')
54 {
55 p = 1;
56 ch = getchar();
57 }
58 while (ch >= '0' && ch <= '9')
59 {
60 sum = sum * 10 + ch - '0';
61 ch = getchar();
62 }
63 return p ? -sum : sum;
64 }
65
66 struct Dinic
67 {
68 int head[maxn], tot, cur[maxn];
69 int dis[maxn];
70 int s, e;
71 queue<int>q;
72
73 struct node
74 {
75 int v, w;
76 int next;
77 }p[maxn];
78
79 void init()
80 {
81 tot = 0;
82 memset(head, -1, sizeof head);
83 }
84
85 void add(int u, int v, int w)
86 {
87 p[tot].v = v;
88 p[tot].w = w;
89 p[tot].next = head[u];
90 head[u] = tot++;
91 }
92
93 void addEdge(int u, int v, int w)
94 {
95 add(u, v, w);
96 add(v, u, 0);
97 }
98
99 bool bfs()
100 {
101 memset(dis, 0, sizeof dis);
102 while (!q.empty()) q.pop();
103 dis[s] = 1;
104 q.push(s);
105 while (!q.empty())
106 {
107 int x = q.front();
108 q.pop();
109 for (int i = head[x]; i != -1; i = p[i].next)
110 {
111 int v = p[i].v, w = p[i].w;
112 if (!dis[v] && w)
113 {
114 dis[v] = dis[x] + 1;
115 q.push(v);
116 }
117 }
118 }
119 if (dis[e]) return true;
120 return false;
121 }
122
123 int dfs(int x, int W)
124 {
125 if (x == e || W == 0) return W;
126 int res = 0;
127 for (int i = cur[x]; i != -1; i = p[i].next)
128 {
129 cur[x] = p[i].next;
130 int v = p[i].v, w = p[i].w;
131 if (dis[v] == dis[x] + 1)
132 {
133 int f = dfs(v, min(w, W));
134 p[i].w -= f;
135 p[i ^ 1].w += f;
136 W -= f;
137 res += f;
138 if (W == 0) break;
139 }
140 }
141 return res;
142 }
143
144 int getMaxFlow()
145 {
146 int ans = 0;
147 while (bfs())
148 {
149 for (int i = s; i <= e; ++i) cur[i] = head[i];
150 ans += dfs(s, inf);
151 }
152 return ans;
153 }
154 }DC;
155
156 struct stortest_Floyd {
157 int a[5000][5000];
158 void floyd(int num) {
159 for (int k = 1; k <= num; k++) {
160 for (int i = 1; i <= num; i++) {
161 for (int j = 1; j <= num; j++) {
162 if (a[i][j] > a[i][k] + a[k][j]) {
163 a[i][j] = a[i][k] + a[k][j];
164 }
165 }
166 }
167 }
168 }
169 }Floyd;
170
171 struct Min_Cost_Max_Flow
172 {
173 struct Edge
174 {
175 int from, to, cap, flow, cost;
176 };
177
178 vector<Edge>edges;
179 vector<int>G[maxn];
180 bool vis[maxn];
181 int d[maxn], p[maxn], a[maxn];
182 int n, m, s, t;
183
184 void init(int n, int s, int t)
185 {
186 this->n = n, this->s = s, this->t = t;
187 for (int i = 1; i <= n; ++i)
188 {
189 G[i].clear();
190 }
191 edges.clear();
192 }
193
194 void add_edge(int from, int to, int cap, int cost)
195 {
196 edges.push_back({ from,to,cap,0,cost });
197 edges.push_back({ to,from,0,0,-cost });
198 m = edges.size();
199 G[from].push_back(m - 2);
200 G[to].push_back(m - 1);
201 }
202
203 bool SPFA(int& flow, int& cost)
204 {
205 memset(d, inf, sizeof d);
206 memset(vis, false, sizeof vis);
207 memset(p, -1, sizeof p);
208 d[s] = 0, vis[s] = true, p[s] = 0, a[s] = inf;
209
210 std::queue<int>que;
211 que.push(s);
212 while (!que.empty())
213 {
214 int u = que.front();
215 que.pop();
216 vis[u] = false;
217 for (int i = 0; i < G[u].size(); ++i)
218 {
219 Edge& e = edges[G[u][i]];
220 if (e.cap > e.flow&& d[e.to] > d[u] + e.cost)
221 {
222 d[e.to] = d[u] + e.cost;
223 p[e.to] = G[u][i];
224 a[e.to] = std::min(a[u], e.cap - e.flow);
225 if (!vis[e.to])
226 {
227 vis[e.to] = true;
228 que.push(e.to);
229 }
230 }
231 }
232 }
233
234 if (d[t] == inf) return false;
235 flow += a[t];
236 cost += d[t] * a[t];
237 int u = t;
238 while (u != s)
239 {
240 edges[p[u]].flow += a[t];
241 edges[p[u] ^ 1].flow -= a[t];
242 u = edges[p[u]].from;
243 }
244 return true;
245 }
246
247 void solve(int& flow, int& cost)
248 {
249 flow = cost = 0;
250 while (SPFA(flow, cost));
251 }
252 };
253
254 char s[maxn][maxn];
255 vector<pii>house, man;
256
257 int main()
258 {
259 int n, m;
260 while (~scanf("%d %d", &n, &m))
261 {
262 if (n + m == 0) break;
263 house.clear(), man.clear();
264 for (int i = 1; i <= n; ++i)
265 {
266 scanf("%s", s[i] + 1);
267 for (int j = 1; j <= m; ++j)
268 {
269 if (s[i][j] == 'H')
270 house.push_back({ i,j });
271 else if (s[i][j] == 'm')
272 man.push_back({ i,j });
273 }
274 }
275
276 int sz1 = man.size(), sz2 = house.size();
277 int st = 0, ed = sz1 + sz2 + 1;
278 Min_Cost_Max_Flow mcmf;
279 mcmf.init(ed + 1, st, ed);
280 for (int i = 0; i < sz1; ++i)
281 {
282 mcmf.add_edge(st, i + 1, 1, 0);
283 int x1 = man[i].first, y1 = man[i].second;
284 for (int j = 0; j < sz2; ++j)
285 {
286 int x2 = house[j].first, y2 = house[j].second;
287 mcmf.add_edge(i + 1, sz1 + j + 1, 1, abs(x1 - x2) + abs(y1 - y2));
288 }
289 }
290 for (int i = 0; i < sz2; ++i)
291 mcmf.add_edge(i + sz1 + 1, ed, 1, 0);
292 int flow, cost;
293 mcmf.solve(flow, cost);
294 cout << cost << endl;
295 }
296 }