1. 程式人生 > >CF1059D Nature Reserve (精度處理,計算幾何,二分)

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 }