代码源oj 648.快速集合

648.快速集合

数轴上有 n 个人,他们要选一个地点集合。第 i 个人初始在位置 ai 上,他的移速最大是 bi 单位/秒,请问最少需要花费多少秒,这 n 个人可以在某一个点集合。

输入格式
输入第一行一个数 n。

接下来 n 行每行两个整数 ai,bi

输出格式
输出一个数表示答案。相对误差或绝对误差在 10−6 内即为正确。

样例输入

2
1 2
5 2

样例输出

1.0000000000

数据规模
对于 100% 的数据,保证 1≤n≤100000,1≤ai,bi≤100000。
.
.
.

思路

这一题不太会写,听完讲解之后,看了好久wls的代码才看懂了一点点。
这个题让我想起来了前几个星期leetcode的某一周的周赛的第三题,好像也是二分

大概思路就是 对时间进行二分

而且,经过wls的讲解,不要写 l + eps < r 作为循环结束的条件,好像是因为c++中的浮点数的存储并不是连续的,我们可以自己算一下最多会二分多少次,然后设置一个稍微大一点点的循环次数,防止浮点数的错误。

因为题目要找到所有点可以同时到达某个点的最小的时间,每个点都有自己对的移动速度,就是要找到这n个区间的交集,如果某一时刻有交集,说明可以在这个时刻同时到达某一点,否则就不能同时到达某一点。

找交集:n个区间的 左端点最大值和右端点最小值,中间夹的就是交集的部分
所以我们二分时间,不断的缩小时间 x = 左端点最大值,y = 右端点最小值

某一点在某一时刻的总范围 = (a[i] - b[i] * t , a[i] + b[i] * t);
即向左走,和向右走 t 秒的距离

如果 x > y 的话代表没有交集,l 的 值选的太小了,导致m 太小了,向左走的时间太短了,应该选大一点
否则的话,到m也满足情况,我们就缩小范围,r = m,找满足条件的最小时间

代码

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
#include 
#include 

using namespace std;
/*
*  求在某一个点集合,那就是求某个时刻n个区间有交集
*  交集就是,左端点的最大值和右端点的最小值是否合理
*  二分时间
*/

int a[100001], b[100001], n;
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++)
    scanf("%d%d", &a[i], &b[i]);
  double l = 0, r = 1e6;
  for (int i = 1; i <= 200; i++) {
    double x = -1e9, y = 1e9, m = (l + r) / 2;
    for (int j = 1; j <= n; j++) {
      x = max(x, a[j] - b[j] * m);
      y = min(y, a[j] + b[j] * m);
    }
    if (x > y)
      l = m;
    else
      r = m; 
  }
  printf("%.6lf\n", l);

  return 0;
}

你可能感兴趣的:(算法,#,二分,leetcode,数据结构,算法)