CF1059D Nature Reserve (精度处理,计算几何,二分)

CF1059D Nature Reserve (精度处理,计算几何,二分)

题目链接:CF1059D

首先处理无解情况,如果在 $x$ 轴两侧都有点,则无解。

我们在将所有 $y$ 值都变为正数方便处理

如果圆与 $x$ 轴相切,则该圆的一条半径垂直于 $x$ 轴。

于是我们可以二分半径 $R$ 

那么圆心的纵坐标是确定的,那么我们如何判断该半径能否覆盖所有圆呢?

如图我们根据勾股定理算出圆心的 $横坐标$ 的的集合

我们可以算出 $X_圆$ $le$  $X+sqrt{R^{2}-(Y-R)^{2}} $    $ps$:上图有点 $bug$

       $X_圆$ $ge$  $X-sqrt{R^{2}-(Y-R)^{2}} $

则所有点的并集为空则不成立,反之成立

以上写在 $check$ 函数中

然后就是二分答案

精度问题:

因为题目要求是与正确答案相对相差1e-6即可,所以我们将eps设为期望答案大小的1e-7被即可,防止超时,卡精度

 1 #include<bits/stdc++.h>
 2 #define MAXN 100010
 3 using namespace std;
 4 struct Point{
 5     int x,y;
 6 }a[MAXN];
 7 int n;
 8 bool f1,f2;
 9 bool check (double k)
10 {
11     double L=-1e15,R=1e15;
12     for (int i=1;i<=n;i++)
13     {
14         double tmp=a[i].y*(2*k-a[i].y);
15         if (tmp<0) return 0;
16         tmp=sqrt (tmp);
17         L=max (L,a[i].x-tmp);R=min (R,a[i].x+tmp);
18     }
19     return L<=R;
20 }
21 int main()
22 {
23     scanf ("%d",&n);
24     int Min_B=1e9,Max_B=-1e9,High=-1e9;
25     for (int i=1;i<=n;i++)
26     {
27         scanf ("%d%d",&a[i].x,&a[i].y);
28         Min_B=min (Min_B,a[i].x);
29         Max_B=max (Max_B,a[i].x);
30         High=max (High,abs (a[i].y));
31         if (a[i].y>0) f1=1;
32         if (a[i].y<0) f2=1;
33     }
34     if (f1&&f2)
35     {
36         printf ("-1");
37         return 0;
38     }
39     if (f2) for (int i=1;i<=n;i++) a[i].y=-a[i].y;
40     double l=0,r=1e14;
41     double eps=max (High,(Max_B-Min_B))*1e-8;
42     while (r-l>eps)
43     {
44         double mid=(l+r)/2;
45         if (check (mid)) r=mid;
46         else l=mid;
47     }
48     printf ("%.7lf",r);
49     return 0;
50 }
原文地址:https://www.cnblogs.com/PaulShi/p/10078337.html