题目大意:
有一个最大是100 * 100 的网格图,上面有 s 个 房子和人,人每移动一个格子花费1的代价,求最小代价让所有的人都进入一个房子。每个房子只能进入一个人。
算法讨论:
注意是KM 和 MCMF算法,我写的是MCMF算法,一开始想的是连10000个点,但是不会连那些大众点之间的边,只会连超级点和普通点之间的边。后来觉得只要连房子点和
人点就可以了。连从人到房子的边,容量是1,花费是他们之间的曼哈顿距离,然后超级源点和超级汇点像上面那样连接,注意连点的时候把他们每个点都具体化一下,就是把点值
都精确到一个连续的范围内去。然后做从超级源点到超级汇点的MCMF算法就可以了。至于那10000个之间的连边,觉得虽然效率不高,但是还是有必要考虑一下。大家有知道的撒
告诉一下。感谢万分。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <queue> 7 8 using namespace std; 9 10 struct MCMF{ 11 static const int N = 200 * 200 + 5; 12 static const int M = 200 * 200 * 4 + 100; 13 static const int oo = 0x3f3f3f3f; 14 15 int n, m, s, t, tot; 16 int first[N], next[M]; 17 int u[M], v[M], cap[M], flow[M], cost[M]; 18 int dis[N], a[N], inque[N], pre[N]; 19 20 void Clear(){memset(first, -1, sizeof first);tot = 0;} 21 22 void Add(int from, int to, int cp, int flw, int ct){ 23 u[tot] = from; v[tot] = to; cap[tot] = cp; flow[tot] = 0; cost[tot] = ct; 24 next[tot] = first[u[tot]]; 25 first[u[tot]] = tot; ++ tot; 26 u[tot] = to; v[tot] = from; cap[tot] = 0; flow[tot] = 0; cost[tot] = -ct; 27 next[tot] = first[u[tot]]; 28 first[u[tot]] = tot; ++ tot; 29 } 30 31 bool bfs(int &flw, int &ct){ 32 for(int i = 0; i <= n + 1; ++ i) dis[i] = oo; 33 memset(inque, 0, sizeof inque); 34 dis[s] = 0; pre[s] = 0; a[s] = oo; inque[s] = 1; 35 36 queue <int> q; 37 q.push(s); 38 while(!q.empty()){ 39 int now = q.front(); q.pop(); 40 inque[now] = 0; 41 42 for(int i = first[now]; i != -1; i = next[i]){ 43 if(cap[i] > flow[i] && dis[v[i]] > dis[now] + cost[i]){ 44 dis[v[i]] = dis[now] + cost[i]; 45 a[v[i]] = min(a[now], cap[i] - flow[i]); 46 pre[v[i]] = i; 47 if(!inque[v[i]]){ 48 inque[v[i]] = 1; q.push(v[i]); 49 } 50 } 51 } 52 } 53 54 if(dis[t] == oo) return false; 55 flw += a[t]; 56 ct += dis[t] * a[t]; 57 58 int now = t; 59 while(now != s){ 60 flow[pre[now]] += a[t]; 61 flow[pre[now]^1] -= a[t]; 62 now = u[pre[now]]; 63 } 64 return true; 65 } 66 67 int MinCostMaxFlow(int s, int t){ 68 this->s = s;this->t = t; 69 int flw = 0, ct = 0; 70 while(bfs(flw, ct)); 71 return ct; 72 } 73 }Net; 74 75 struct Position{ 76 int l, r, id; 77 Position(int _l=0, int _r=0, int _id=0): l(_l), r(_r), id(_id){} 78 }mm[205], HH[205]; 79 80 int ns, ms, cnt1, cnt2, tp1, tp2; 81 char str[105][105]; 82 83 void Solve(){ 84 for(int i = 1; i <= tp1; ++ i){ 85 for(int j = 1; j <= tp2; ++ j){ 86 int x1 = mm[i].l, y1 = mm[i].r; 87 int x2 = HH[j].l, y2 = HH[j].r; 88 Net.Add(mm[i].id, HH[j].id, 1, 0, abs(x1-x2) + abs(y1-y2)); 89 } 90 } 91 } 92 93 int main(){ 94 95 while(scanf("%d%d", &ns, &ms) && ns && ms){ 96 Net.Clear(); 97 cnt1 = cnt2 = 0; 98 tp1 = tp2 = 0; 99 for(int i = 1; i <= ns; ++ i) 100 scanf("%s", str[i] + 1); 101 for(int i = 1; i <= ns; ++ i){ 102 for(int j = 1; j <= ms; ++ j){ 103 if(str[i][j] == 'm') ++ tp1; 104 else if (str[i][j] == 'H') ++ tp2; 105 } 106 } 107 Net.n = tp1 + tp2; 108 for(int i = 1; i <= ns; ++ i){ 109 for(int j = 1; j <= ms; ++ j){ 110 if(str[i][j] == 'm'){ 111 ++ cnt1; 112 Net.Add(0, cnt1, 1, 0, 0); 113 mm[cnt1] = (Position){i, j, cnt1}; 114 } 115 } 116 } 117 for(int i = 1; i <= ns; ++ i){ 118 for(int j = 1; j <= ms; ++ j){ 119 if(str[i][j] == 'H'){ 120 ++ cnt2; 121 Net.Add(tp1 + cnt2, Net.n + 1, 1, 0, 0); 122 HH[cnt2] = (Position){i, j, tp1 + cnt2}; 123 } 124 } 125 } 126 Solve(); 127 printf("%d ", Net.MinCostMaxFlow(0, Net.n + 1)); 128 } 129 130 return 0; 131 }