Going Home
On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.
Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point.
You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
Input
There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.
Output
For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.
Sample Input
2 2
.m
H.
5 5
HH..m
.....
.....
.....
mm..H
7 8
...H....
...H....
...H....
mmmHmmmm
...H....
...H....
...H....
0 0
Sample Output
2
10
28
Source
题目类型:最小费用最大流
算法分析:从每个人开始bfs找到所有的房子,从这个人向这个房子连一条容量为1,花费为两者距离的有向边,然后从源点向每个人连一条容量为1,花费为0的有向边,从每个房子向汇点连一条容量为1,花费为0的有向边,最后跑个最小费用流即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
/************************************************* Author :supermaker Created Time :2016/4/4 20:01:51 File Location :C:\Users\abcd\Desktop\TheEternalPoet **************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <set> #include <bitset> #include <list> #include <map> #include <stack> #include <queue> #include <deque> #include <string> #include <vector> #include <ios> #include <iostream> #include <fstream> #include <sstream> #include <iomanip> #include <algorithm> #include <utility> #include <complex> #include <numeric> #include <functional> #include <cmath> #include <ctime> #include <climits> #include <cstdarg> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cassert> using namespace std; #define CFF freopen ("aaa.txt", "r", stdin) #define CPPFF ifstream cin ("aaa.txt") #define DB(ccc) cout << #ccc << " = " << ccc << endl #define PB push_back #define MP(A, B) make_pair(A, B) typedef long long LL; typedef unsigned long long ULL; typedef double DB; typedef pair <int, int> PII; typedef pair <int, bool> PIB; const int INF = 0x7F7F7F7F; const int MOD = 1e9 + 7; const double EPS = 1e-10; const double PI = 2 * acos (0.0); const int maxn = 200 + 66; const int dx[] = {0, 0, -1, 1}; const int dy[] = {-1, 1, 0, 0}; struct Node { int to, nxt, c, f, cost; Node () {} Node (int tt, int nn, int cc, int ff, int cco) : to (tt), nxt (nn), c (cc), f (ff), cost (cco) {} }; Node edge[maxn*maxn]; int head[maxn], edgelen; void Init () { memset (head, -1, sizeof (head)); memset (edge, -1, sizeof (edge)); edgelen = 0; } void AddEdge (int cost, int u, int v, int w, int rw = 0) { edge[edgelen].to = v, edge[edgelen].c = w, edge[edgelen].f = 0; edge[edgelen].cost = cost, edge[edgelen].nxt = head[u], head[u] = edgelen++; edge[edgelen].to = u, edge[edgelen].c = rw, edge[edgelen].f = 0; edge[edgelen].cost = -cost, edge[edgelen].nxt = head[v], head[v] = edgelen++; } int dis[maxn], cnt[maxn], inq[maxn], par[maxn]; int N; bool spfa (int s, int e) { for (int i = 0; i <= N; i++) { dis[i] = INF; inq[i] = cnt[i] = 0; par[i] = -1; } dis[s] = 0; queue <int> qu; qu.push (s); inq[s]++, cnt[s]++; while (!qu.empty ()) { int u = qu.front (); qu.pop (); inq[u]--; if (cnt[u] > N) return false; for (int i = head[u]; i != -1; i = edge[i].nxt) { int v = edge[i].to; if (edge[i].c > edge[i].f && dis[u] < INF && dis[v] > dis[u] + edge[i].cost) { dis[v] = dis[u] + edge[i].cost; par[v] = i; if (!inq[v]) { qu.push (v); inq[v]++, cnt[v]++; } } } } if (par[e] == -1) return false; return true; } int allcost; int MinCostMaxFlow (int s, int e) { int res = 0; allcost = 0; while (spfa (s, e)) { int minval = INF; for (int i = par[e]; i != -1; i = par[edge[i^1].to]) minval = min (minval, edge[i].c - edge[i].f); for (int i = par[e]; i != -1; i = par[edge[i^1].to]) { edge[i].f += minval; edge[i^1].f -= minval; allcost += edge[i].cost * minval; } res += minval; } return res; } char g[maxn][maxn]; int id[maxn][maxn], len, row, col; bool vis[maxn][maxn]; inline bool InLine (int x, int y) { if (x >= 1 && x <= row && y >= 1 && y <= col) return true; return false; } void bfs (int x, int y) { memset (vis, false, sizeof (vis)); vis[x][y] = true; queue <Node> qu; qu.push (Node (x, y, 0, 0, 0)); while (!qu.empty ()) { Node tt = qu.front (); qu.pop (); if (g[tt.to][tt.nxt] == 'H') { AddEdge (tt.c, id[x][y], id[tt.to][tt.nxt], 1); //cout << id[x][y] << " " << id[tt.to][tt.nxt] << " " << tt.c << endl; } for (int i = 0; i < 4; i++) { int xx = tt.to + dx[i], yy = tt.nxt + dy[i]; if (InLine (xx, yy) && !vis[xx][yy]) { vis[xx][yy] = true; qu.push (Node (xx, yy, tt.c + 1, 0, 0)); } } } } int main() { //CFF; //CPPFF; while (scanf ("%d%d", &row, &col) != EOF) { if (row == 0 && col == 0) break; memset (id, -1, sizeof (id)); len = 1; for (int i = 1; i <= row; i++) for (int j = 1; j <= col; j++) { scanf (" %c", &g[i][j]); if (g[i][j] != '.') id[i][j] = len++; } Init (); for (int i = 1; i <= row; i++) for (int j = 1; j <= col; j++) if (g[i][j] == 'm') bfs (i, j); len--; N = len + 2; for (int i = 1; i <= row; i++) for (int j = 1; j <= col; j++) { if (g[i][j] == 'm') AddEdge (0, 0, id[i][j], 1); else if (g[i][j] == 'H') AddEdge (0, id[i][j], len + 1, 1); } MinCostMaxFlow (0, len + 1); printf ("%d\n", allcost); } return 0; } |