首页 > 代码库 > 北工大2017校赛 1101:要打车的FanZzz

北工大2017校赛 1101:要打车的FanZzz

题目链接:

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\n", edges[res] / v);
121     }
122     return 0;
123 }

 

北工大2017校赛 1101:要打车的FanZzz