题目链接:https://vjudge.net/problem/POJ-2195
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 24015 | Accepted: 12054 |
Description
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
Output
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
题意:
给出一张n*m的图,其中里面有数量相等的人和房屋。下雨了,要为每个人安排一座房屋,且每个房屋只能容纳一个人。问:怎样安排,才能使得总的路程最短(不用考虑房屋与人的阻碍问题,即两点距离直接是曼哈顿距离)?
题解:
最大权匹配的裸题,把权值取反即可。或者用最小费用最大流去做也可以。
最大权匹配:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int mod = 1e9+7; 17 const int MAXN = 1e2+10; 18 19 int nx, ny; 20 int g[MAXN][MAXN]; 21 int linker[MAXN], lx[MAXN], ly[MAXN]; 22 int slack[MAXN]; 23 bool visx[MAXN], visy[MAXN]; 24 25 bool DFS(int x) 26 { 27 visx[x] = true; 28 for(int y = 1; y<=ny; y++) 29 { 30 if(visy[y]) continue; 31 int tmp = lx[x] + ly[y] - g[x][y]; 32 if(tmp==0) 33 { 34 visy[y] = true; 35 if(linker[y]==-1 || DFS(linker[y])) 36 { 37 linker[y] = x; 38 return true; 39 } 40 } 41 else 42 slack[y] = min(slack[y], tmp); 43 } 44 return false; 45 } 46 47 int KM() 48 { 49 memset(linker, -1, sizeof(linker)); 50 memset(ly, 0, sizeof(ly)); 51 for(int i = 1; i<=nx; i++) 52 { 53 lx[i] = -INF; 54 for(int j = 1; j<=ny; j++) 55 lx[i] = max(lx[i], g[i][j]); 56 } 57 58 for(int x = 1; x<=nx; x++) 59 { 60 for(int i = 1; i<=ny; i++) 61 slack[i] = INF; 62 while(true) 63 { 64 memset(visx, 0, sizeof(visx)); 65 memset(visy, 0, sizeof(visy)); 66 67 if(DFS(x)) break; 68 int d = INF; 69 for(int i = 1; i<=ny; i++) 70 if(!visy[i]) 71 d = min(d, slack[i]); 72 73 for(int i = 1; i<=nx; i++) 74 if(visx[i]) 75 lx[i] -= d; 76 for(int i = 1; i<=ny; i++) 77 { 78 if(visy[i]) ly[i] += d; 79 else slack[i] -= d; 80 } 81 } 82 } 83 84 int res = 0; 85 for(int i = 1; i<=ny; i++) 86 if(linker[i]!=-1) 87 res += g[linker[i]][i]; 88 return res; 89 } 90 91 int house[MAXN][2], man[MAXN][2]; 92 int main() 93 { 94 int n, m; 95 char str[MAXN]; 96 while(scanf("%d%d",&n,&m)&&(m||n)) 97 { 98 nx = 0, ny = 0; 99 for(int i = 1; i<=n; i++) 100 { 101 scanf("%s", str+1); 102 for(int j = 1; j<=m; j++) 103 { 104 if(str[j]=='H') house[++nx][0] = i, house[nx][1] = j; 105 else if(str[j]=='m') man[++ny][0] = i, man[ny][1] = j; 106 } 107 } 108 109 memset(g, 0, sizeof(g)); 110 for(int i = 1; i<=nx; i++) 111 for(int j = 1; j<=ny; j++) 112 g[i][j] = -(abs(house[i][0]-man[j][0])+abs(house[i][1]-man[j][1])); 113 114 int ans = -KM(); 115 printf("%d\n", ans); 116 } 117 }
最小费用最大流:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <string> 11 #include <set> 12 using namespace std; 13 typedef long long LL; 14 const int INF = 2e9; 15 const LL LNF = 9e18; 16 const int mod = 1e9+7; 17 const int MAXN = 1e3+10; 18 19 struct Edge 20 { 21 int to, next, cap, flow, cost; 22 }edge[10010<<2]; 23 int tot, head[MAXN]; 24 int pre[MAXN], dis[MAXN]; 25 bool vis[MAXN]; 26 int N; 27 28 void init(int n) 29 { 30 N = n; 31 tot = 0; 32 memset(head, -1, sizeof(head)); 33 } 34 35 void add(int u, int v, int cap, int cost) 36 { 37 edge[tot].to = v; edge[tot].cap = cap; edge[tot].cost = cost; 38 edge[tot].flow = 0; edge[tot].next = head[u]; head[u] = tot++; 39 40 edge[tot].to = u; edge[tot].cap = 0; edge[tot].cost = -cost; 41 edge[tot].flow = 0; edge[tot].next = head[v]; head[v] = tot++; 42 } 43 44 bool spfa(int s, int t) 45 { 46 queue<int>q; 47 for(int i = 0; i<N; i++) 48 { 49 dis[i] = INF; 50 vis[i] = false; 51 pre[i] = -1; 52 } 53 54 dis[s] = 0; 55 vis[s] = true; 56 q.push(s); 57 while(!q.empty()) 58 { 59 int u = q.front(); 60 q.pop(); 61 vis[u] = false; 62 for(int i = head[u]; i!=-1; i = edge[i].next) 63 { 64 int v = edge[i].to; 65 if(edge[i].cap>edge[i].flow && dis[v]>dis[u]+edge[i].cost) 66 { 67 dis[v] = dis[u]+edge[i].cost; 68 pre[v] = i; 69 if(!vis[v]) 70 { 71 vis[v] = true; 72 q.push(v); 73 } 74 } 75 } 76 } 77 if(pre[t]==-1) return false; 78 return true; 79 } 80 81 int minCostMaxFlow(int s, int t, int &cost) 82 { 83 int flow = 0; 84 cost = 0; 85 while(spfa(s,t)) 86 { 87 int Min = INF; 88 for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to]) 89 { 90 if(Min>edge[i].cap-edge[i].flow) 91 Min = edge[i].cap-edge[i].flow; 92 } 93 for(int i = pre[t]; i!=-1; i = pre[edge[i^1].to]) 94 { 95 edge[i].flow += Min; 96 edge[i^1].flow -= Min; 97 cost += edge[i].cost*Min; 98 } 99 flow += Min; 100 } 101 return flow; 102 } 103 104 int house[MAXN][2], man[MAXN][2]; 105 int main() 106 { 107 int n, m; 108 char str[MAXN]; 109 while(scanf("%d%d",&n,&m)&&(m||n)) 110 { 111 int nx = 0, ny = 0; 112 for(int i = 1; i<=n; i++) 113 { 114 scanf("%s", str+1); 115 for(int j = 1; j<=m; j++) 116 { 117 if(str[j]=='H') house[++nx][0] = i, house[nx][1] = j; 118 else if(str[j]=='m') man[++ny][0] = i, man[ny][1] = j; 119 } 120 } 121 122 init(nx+ny+2); 123 for(int i = 1; i<=nx; i++) 124 for(int j = 1; j<=ny; j++) 125 add(i,nx+j,1,abs(house[i][0]-man[j][0])+abs(house[i][1]-man[j][1])); 126 127 for(int i = 1; i<=nx; i++) add(0,i,1,0); 128 for(int i = 1; i<=ny; i++) add(nx+i,nx+ny+1,1,0); 129 130 int mincost; 131 minCostMaxFlow(0, nx+ny+1, mincost); 132 printf("%d\n", mincost); 133 } 134 }