题目链接:
http://bjutacm.openjudge.cn/lianxi/1101/
思路:
二分 + 二分图最大匹配。
开始的时候我想直接用最小费用流模型,后来发现这样是错误的。因为这道题实际上是求一个匹配数>=n的匹配,并且满足在这个匹配中匹配边的最大的权值最小;而不是使所有匹配边的权值之和最小。这样看来就是一个典型的二分思路。首先对权值排序,每次选中原图中那些权值不能超过x的边,用这些边构建二分图。再用匈牙利算法check一下这个二分图的最大匹配数是否>=n。二分一下满足这样的条件下对应的最小的那个边权值x即可。
实现:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int MAXN = 200; 9 int n, m; 10 double v, dis[MAXN + 5][MAXN + 5], edges[MAXN * MAXN + 5]; 11 vector<int> G[MAXN + 5]; 12 bool used[MAXN + 5]; 13 int match[MAXN + 5]; 14 15 struct point 16 { 17 int x, y; 18 }; 19 point man[MAXN / 2 + 5], car[MAXN / 2 + 5]; 20 21 bool dfs(int v) 22 { 23 used[v] = true; 24 for (int i = 0; i < G[v].size(); i++) 25 { 26 int u = G[v][i]; 27 int w = match[u]; 28 if (w == -1 || !used[w] && dfs(w)) 29 { 30 match[v] = u; 31 match[u] = v; 32 return true; 33 } 34 } 35 return false; 36 } 37 38 int max_match() 39 { 40 int res = 0; 41 for (int i = 1; i <= n + m; i++) 42 { 43 if (match[i] == -1) 44 { 45 memset(used, 0, sizeof(used)); 46 if (dfs(i)) 47 res++; 48 } 49 } 50 return res; 51 } 52 53 bool check(double len) 54 { 55 for (int i = 1; i <= n + m; i++) 56 match[i] = -1; 57 memset(used, 0, sizeof(used)); 58 for (int i = 1; i <= n + m; i++) 59 G[i].clear(); 60 for (int i = 0; i < n; i++) 61 { 62 for (int j = 0; j < m; j++) 63 { 64 if (dis[i][j] <= len) 65 { 66 G[i + 1].push_back(j + n + 1); 67 G[j + n + 1].push_back(i + 1); 68 } 69 } 70 } 71 return max_match() >= n; 72 } 73 74 int square(int x) 75 { 76 return x * x; 77 } 78 79 double cal_cost(int i, int j) 80 { 81 return sqrt(square(man[i].x - car[j].x) + square(man[i].y - car[j].y)); 82 } 83 84 int main() 85 { 86 while (cin >> n >> m) 87 { 88 for (int i = 0; i < n; i++) 89 { 90 cin >> man[i].x >> man[i].y; 91 } 92 for (int i = 0; i < m; i++) 93 { 94 cin >> car[i].x >> car[i].y; 95 } 96 cin >> v; 97 int cnt = 0; 98 for (int i = 0; i < n; i++) 99 { 100 for (int j = 0; j < m; j++) 101 { 102 edges[cnt++] = dis[i][j] = cal_cost(i, j); 103 } 104 } 105 sort(edges, edges + cnt); 106 int l = 0, r = cnt - 1, res = cnt - 1; 107 while (l <= r) 108 { 109 int mid = l + r >> 1; 110 if (check(edges[mid])) 111 { 112 res = mid; 113 r = mid - 1; 114 } 115 else 116 { 117 l = mid + 1; 118 } 119 } 120 printf("%.2lf ", edges[res] / v); 121 } 122 return 0; 123 }