CF1059D Nature Reserve (精度處理,計算幾何,二分)
阿新 • • 發佈:2018-12-06
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 }