POJ2112 Optimal Milking —— 二分图多重匹配/最大流 + 二分
题目链接:https://vjudge.net/problem/POJ-2112
Optimal Milking
Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 18555 | Accepted: 6626 | |
Case Time Limit: 1000MS |
Description
FJ has moved his K (1 <= K <= 30) milking machines out into the cow pastures among the C (1 <= C <= 200) cows. A set of paths of various lengths runs among the cows and the milking machines. The milking machine locations are named by ID numbers 1..K; the cow locations are named by ID numbers K+1..K+C.
Each milking point can "process" at most M (1 <= M <= 15) cows each day.
Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine.
Each milking point can "process" at most M (1 <= M <= 15) cows each day.
Write a program to find an assignment for each cow to some milking machine so that the distance the furthest-walking cow travels is minimized (and, of course, the milking machines are not overutilized). At least one legal assignment is possible for all input data sets. Cows can traverse several paths on the way to their milking machine.
Input
* Line 1: A single line with three space-separated integers: K, C, and M.
* Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line.
* Lines 2.. ...: Each of these K+C lines of K+C space-separated integers describes the distances between pairs of various entities. The input forms a symmetric matrix. Line 2 tells the distances from milking machine 1 to each of the other entities; line 3 tells the distances from machine 2 to each of the other entities, and so on. Distances of entities directly connected by a path are positive integers no larger than 200. Entities not directly connected by a path have a distance of 0. The distance from an entity to itself (i.e., all numbers on the diagonal) is also given as 0. To keep the input lines of reasonable length, when K+C > 15, a row is broken into successive lines of 15 numbers and a potentially shorter line to finish up a row. Each new row begins on its own line.
Output
A single line with a single integer that is the minimum possible total distance for the furthest walking cow.
Sample Input
2 3 2 0 3 2 1 1 3 0 3 2 0 2 3 0 1 0 1 2 1 0 2 1 0 0 2 0
Sample Output
2
Source
题解:
题意:有n头牛, m个挤奶器(只能为个数限定的牛挤奶)。每头牛和挤奶器都有其固定的位置。主人安排每头牛去某个挤奶器中挤奶,且在途中,牛可以经过其他地方。为了节省牛的体力,主人希望路途最长的那头牛的路途尽可能短(最大值最小)。
1.用Floyd算法求出每头牛到每个挤奶器的最短路径。
2.二分最长路径,然后重新建图,如果某条路径的长度小于等于最长路径,则连起两端点;否则,两端点没有连接。
3.利用二分图多重匹配或者最大流,求出是否每头牛都能在某台挤奶器中挤奶。如果可以,则减小最长路径;否则增大最长路径。
多重匹配:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <queue> 10 #include <sstream> 11 #include <algorithm> 12 using namespace std; 13 const int INF = 2e9; 14 const int MOD = 1e9+7; 15 const int MAXM = 5e2+10; 16 const int MAXN = 4e2+10; 17 18 int uN, vN, m, N, maze[MAXN][MAXN]; 19 int num[MAXM], linker[MAXM][MAXN]; 20 bool g[MAXN][MAXM], used[MAXM]; 21 22 bool dfs(int u) 23 { 24 for(int v = 1; v<=vN; v++) 25 if(g[u][v] && !used[v]) 26 { 27 used[v] = true; 28 if(linker[v][0]<num[v]) 29 { 30 linker[v][++linker[v][0]] = u; 31 return true; 32 } 33 for(int i = 1; i<=num[v]; i++) 34 if(dfs(linker[v][i])) 35 { 36 linker[v][i] = u; 37 return true; 38 } 39 } 40 return false; 41 } 42 43 bool hungary(int mid) 44 { 45 memset(g, false, sizeof(g)); 46 for(int i = vN+1; i<=N; i++) 47 for(int j = 1; j<=vN; j++) 48 if(maze[i][j]<=mid) 49 g[i][j] = true; 50 51 for(int i = 1; i<=vN; i++) 52 { 53 num[i] = m; 54 linker[i][0] = 0; 55 } 56 for(int u = vN+1; u<=N; u++) 57 { 58 memset(used, false, sizeof(used)); 59 if(!dfs(u)) return false; 60 } 61 return true; 62 } 63 64 void Flyod() 65 { 66 for(int k = 1; k<=N; k++) 67 for(int i = 1; i<=N; i++) 68 for(int j = 1; j<=N; j++) 69 maze[i][j] = min(maze[i][j], maze[i][k]+maze[k][j]); 70 } 71 72 int main() 73 { 74 while(scanf("%d%d%d", &vN, &uN, &m)!=EOF) 75 { 76 N = uN + vN; 77 for(int i = 1; i<=N; i++) 78 for(int j = 1; j<=N; j++) 79 { 80 scanf("%d", &maze[i][j]); 81 if(maze[i][j]==0) maze[i][j] = INF/2; 82 } 83 84 Flyod(); 85 int l = 1, r = 200*400; 86 while(l<=r) 87 { 88 int mid = (l+r)>>1; 89 if(hungary(mid)) 90 r = mid - 1; 91 else 92 l = mid + 1; 93 } 94 printf("%d\n", l); 95 } 96 }
最大流:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <queue> 10 #include <sstream> 11 #include <algorithm> 12 using namespace std; 13 const int INF = 2e9; 14 const int MOD = 1e9+7; 15 const int MAXM = 5e2+10; 16 const int MAXN = 4e2+10; 17 18 struct Edge 19 { 20 int to, next, cap, flow; 21 }edge[MAXN*MAXN]; 22 int tot, head[MAXN]; 23 24 int uN, vN, m, N, maze[MAXN][MAXN]; 25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN]; 26 void add(int u, int v, int w) 27 { 28 edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0; 29 edge[tot].next = head[u]; head[u] = tot++; 30 edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0; 31 edge[tot].next = head[v]; head[v] = tot++; 32 } 33 34 int sap(int start, int end, int nodenum) 35 { 36 memset(dep, 0, sizeof(dep)); 37 memset(gap, 0, sizeof(gap)); 38 memcpy(cur, head, sizeof(head)); 39 int u = pre[start] = start, maxflow = 0,aug = INF; 40 gap[0] = nodenum; 41 while(dep[start]<nodenum) 42 { 43 loop: 44 for(int i = cur[u]; i!=-1; i = edge[i].next) 45 { 46 int v = edge[i].to; 47 if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1) 48 { 49 aug = min(aug, edge[i].cap-edge[i].flow); 50 pre[v] = u; 51 cur[u] = i; 52 u = v; 53 if(v==end) 54 { 55 maxflow += aug; 56 for(u = pre[u]; v!=start; v = u,u = pre[u]) 57 { 58 edge[cur[u]].flow += aug; 59 edge[cur[u]^1].flow -= aug; 60 } 61 aug = INF; 62 } 63 goto loop; 64 } 65 } 66 int mindis = nodenum; 67 for(int i = head[u]; i!=-1; i = edge[i].next) 68 { 69 int v=edge[i].to; 70 if(edge[i].cap-edge[i].flow && mindis>dep[v]) 71 { 72 cur[u] = i; 73 mindis = dep[v]; 74 } 75 } 76 if((--gap[dep[u]])==0)break; 77 gap[dep[u]=mindis+1]++; 78 u = pre[u]; 79 } 80 return maxflow; 81 } 82 83 bool test(int mid) 84 { 85 tot = 0; 86 memset(head, -1, sizeof(head)); 87 for(int i = vN+1; i<=N; i++) 88 { 89 add(0, i, 1); 90 for(int j = 1; j<=vN; j++) 91 if(maze[i][j]<=mid) 92 add(i, j, 1); 93 } 94 for(int i = 1; i<=vN; i++) 95 add(i, N+1, m); 96 97 int maxflow = sap(0, N+1, N+2); 98 return maxflow == uN; 99 } 100 101 void Flyod() 102 { 103 for(int k = 1; k<=N; k++) 104 for(int i = 1; i<=N; i++) 105 for(int j = 1; j<=N; j++) 106 maze[i][j] = min(maze[i][j], maze[i][k]+maze[k][j]); 107 } 108 109 int main() 110 { 111 while(scanf("%d%d%d", &vN, &uN, &m)!=EOF) 112 { 113 N = uN + vN; 114 for(int i = 1; i<=N; i++) 115 for(int j = 1; j<=N; j++) 116 { 117 scanf("%d", &maze[i][j]); 118 if(maze[i][j]==0) maze[i][j] = INF/2; 119 } 120 121 Flyod(); 122 int l = 1, r = 200*400; 123 while(l<=r) 124 { 125 int mid = (l+r)>>1; 126 if(test(mid)) 127 r = mid - 1; 128 else 129 l = mid + 1; 130 } 131 printf("%d\n", l); 132 } 133 }