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. 

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. 

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 }
View Code

 

最大流:

  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 }
View Code

 

posted on 2017-11-12 15:57  h_z_cong  阅读(442)  评论(0编辑  收藏  举报

导航