北工大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 }
时间: 2024-07-29 02:12:10

北工大2017校赛 1101:要打车的FanZzz的相关文章

bnu 51644 Whalyzh&#39;s Problem(网络流,最大密度图) (北师16校赛)

很久以前,当whalyzh同学是一个萌新的时候,遇到了这么一个问题: 给定长为的序列,构造一个只有0和1的长为的序列,使得的值最大. 小Q同学想了一秒钟之后说:这不是一眼题么?然后whalyzh同学瞬间就会了. 过了几天,当whalyzh同学还是一个萌新的时候,遇到了这么一个问题: 给定阶方阵,构造一个只有0和1的的向量,使得的值最大. 小Q同学想了一分钟之后说:这不是一眼题么?然后whalyzh同学瞬间就会了. 又过了几天,当whalyzh仍然是一个萌新的时候,遇到了这么一个问题: 给定阶方阵

河南工业大学2017校赛题解

问题 A: 饶学妹的比赛 题意: 给你一场比赛每人提交的记录,计算最后的排名 题解: 模拟+排序 代码: 1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <stack> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #

广工2017校赛-F-- tmk找三角

http://gdutcode.sinaapp.com/problem.php?cid=1056&pid=5 Description 有一棵树,树上有只tmk.他在这棵树上生活了很久,对他的构造了如指掌.所以他在树上从来都是走最短路,不会绕路.他还还特别喜欢三角形,所以当他在树上爬来爬去的时候总会在想,如果把刚才爬过的那几根树枝/树干锯下来,能不能从中选三根出来拼成一个三角形呢? Input 第一行输入一个T,表示有多少组样例. 对于每组数据:第一行包含一个整数 N,表示树上节点的个数(从 1

bnu 51636 Squared Permutation(树状数组)(北师16校赛)

最近,无聊的过河船同学在玩一种奇怪的名为"小Q的恶作剧"的纸牌游戏. 现在过河船同学手有张牌,分别写着,打乱顺序之后排成一行,位置从左往右按照标号. 接下来小Q同学会给出个操作,分为以下两种: 1.给定,交换从左往右数的第和第张牌, 2.给定,对从左往右数的第张牌,记下位置是这张牌上的数字的牌的数字,询问所有记下的数字加起来的结果. 虽然无聊的过河船同学精通四则运算,但是要完成这么大的计算量还是太辛苦了,希望你能帮他处理这些操作. Input 第一行是一个正整数,表示测试数据的组数,

bnu 51638 Air Hockey(三分+二分)(北师16校赛)

无聊的过河船同学和无聊的胀鱼同学非常喜欢打桌上冰球(其实只是喜欢听球碰撞时的声音).在无聊的一天,无聊的过河船同学想到了一个无聊的玩法:两人同时将两个球放桌面上,同时击出,然后听两颗球撞在一起时的声音.然而他们都对击球的精确度把握得不是很好,所以这两颗球并不一定能相撞. 现在假设桌面无限大,并且绝对光滑,给出两球的初始位置.半径和运动速度,保证两球初始没有接触.无聊的过河船同学想知道两球能否相撞(接触即认为相撞),如果能,他想知道两球相撞的时间(从两人击球时开始计时),如果不能,他想知道全过程中

bnu 51641 Certain Maze(bfs)(北师16校赛)

最近,无聊的过河船同学发现了一种无聊的迷宫生成算法. 算法过程如下: 一个的矩形区域可以看作个单位网格组成.在每个网格中,随机生成一个从右上角到左下角的L型障碍或者从左上角到右下角的R型障碍(障碍可以被看作一条线段). 图1:两种障碍 这样便可以生成一个大小为的迷宫,如图2所示. 图2:无聊的迷宫 然后过河船同学想知道,是否存在迷宫内的从迷宫上边界到达迷宫的下边界的路径.于是无聊的过河船同学花了一夜的时间,终于找到一条路径. 图3:过河船同学辛辛苦苦找到的道路 痛苦的过河船同学不想再伤害自己的眼

bnu 51640 Training Plan(类似区间dp)(北师16校赛)

小Q同学为了准备今年的ICPC Regional,计划在天之内刷掉道题,每道题有一个难度值,其中第道题的难度值为. 然而处于半颓废状态中的小Q同学不希望在同一天中做难度差距悬殊的题目,定义第天中刷的题的难度的最大值减最小值为(如果第天没有刷题,则),那么整个计划的难度为. 小Q同学可以按照任意的顺序刷题,并且一天中可以刷任意多道题,但是每道题只需要做一次,现在小Q同学想知道完成这个计划的总难度的最小值是多少. Input 第一行是一个正整数,表示测试数据的组数, 对于每组测试数据, 第一行是两个

内工大acm校赛--整理代码

题目:小明搜到一行无缩进无换行代码,请帮小明整理代码.无for语句和case语句,而且只有一个主函数.你只要控制注意“:”“{”“}”这三个符号带来的缩进和换行效果就行. Input: 输入只有一行,无缩进无换行字符,字符不超过10000009个.文件尾结束. Output: 规范的缩进和换行,增加和减少缩进都以四个空格为单位. Sample Input: int main(){int a,b,c;while(cin>>a>>b){if(a>b){c=a+b;cout<

四叠半神话大系(bfs序+st+在线倍增+二分)(北理16校赛)

时间限制1秒 内存限制64M 题目描述: 「我们大部分的烦恼,是来自于梦想另一种有可能的人生.把希望寄托于自己的可能性这种不能指望的东西,正是万恶的根源.」 时间突然停止. 我获得了可以在平行世界中穿梭的能力. 宇宙中存在着无数的平行世界,这些世界组成了一个树形的结构,每个世界有一个编号和一个幸福度. 每当我做出选择时,世界会分裂成若干个新的世界.选择会导致幸福度的变化.根据选择的不同,在新的世界里,我可能会变的更加幸福,或者更加不幸. 出于某些原因,我只能在处于相同时间的世界内穿梭,而且只能在