zoukankan      html  css  js  c++  java
  • 北工大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
    ", edges[res] / v);
    121     }
    122     return 0;
    123 }
  • 相关阅读:
    第二周教学设计反思
    uni-app,一套代码应用在多个平台
    新CMS
    学习js
    关于数据库
    自己写的一段jquery实现当滚动条滑动到某个位置实现向中间移动
    js平滑滚动到顶部、底部、指定地方
    统一一个帝国中搜索页面的模板
    帝国CMS的总结
    回到顶部的功能
  • 原文地址:https://www.cnblogs.com/wangyiming/p/6756325.html
Copyright © 2011-2022 走看看