Codeforces #514 D. Nature Reserve(幾何 最小圓覆蓋,三分)
D. Nature Reserve
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
There is a forest that we model as a plane and live nn rare animals. Animal number ii has its lair in the point (xi,yi)(xi,yi). In order to protect them, a decision to build a nature reserve has been made.
The reserve must have a form of a circle containing all lairs. There is also a straight river flowing through the forest. All animals drink from this river, therefore it must have at least one common point with the reserve. On the other hand, ships constantly sail along the river, so the reserve must not have more than one common point with the river.
For convenience, scientists have made a transformation of coordinates so that the river is defined by y=0y=0. Check whether it is possible to build a reserve, and if possible, find the minimum possible radius of such a reserve.
Input
The first line contains one integer nn (1≤n≤1051≤n≤105) — the number of animals.
Each of the next nn lines contains two integers xixi, yiyi (−107≤xi,yi≤107−107≤xi,yi≤107) — the coordinates of the ii-th animal's lair. It is guaranteed that yi≠0yi≠0. No two lairs coincide.
Output
If the reserve cannot be built, print −1−1. Otherwise print the minimum radius. Your answer will be accepted if absolute or relative error does not exceed 10−610−6.
Formally, let your answer be aa, and the jury's answer be bb. Your answer is considered correct if |a−b|max(1,|b|)≤10−6|a−b|max(1,|b|)≤10−6.
Examples
input
Copy
1 0 1
output
Copy
0.5
input
Copy
3 0 1 0 2 0 -3
output
Copy
-1
input
Copy
2 0 1 1 1
output
Copy
0.625
Note
In the first sample it is optimal to build the reserve with the radius equal to 0.50.5 and the center in (0, 0.5)(0, 0.5).
In the second sample it is impossible to build a reserve.
In the third sample it is optimal to build the reserve with the radius equal to 5858 and the center in (12, 58)(12, 58).
【體驗感】
當機會擺在眼前,我卻沒有珍惜它,等到被eps卡炸,我菜追悔莫及。long double的有效位數18位,能解方程的問題我非要二分查詢,這題答案最大能到1e14,還剩4位能給eps用,eps最小隻能1e-4了,再小就跑死了。這題答案要求誤差1e-6。把自己搞死了。 為什麼要二分?為什麼要二分?明明解一解方程就能求的事情,懶,是懶,懶到不想寫方程,懶到二分暴力一下。
求與x軸相切的最小圓覆蓋。
【題意】
平面上給出一些點(注意資料範圍),求一個最小的圓的半徑,滿足此圓覆蓋所有點並且與x軸相切!
【分析】
經驗算,圓的半徑最壞情況能到1e14,導致了我的【體驗感】。
易知,這個圓的圓心座標x,越靠中間,其可行圓的半徑越小,因此可以用三分找到這個x座標。但是三分時需要求的當前x座標下的半徑是多少?
下面求給定x座標後的半徑:對於任意一點(x1,y1),設最小圓圓心(x,y),半徑r,則滿足:r==y && r*r==(y-y1)*(y-y1)+(x-x1)*(x-x1);解方程即可得到精確的y,也就是r!(而我當時傻的一批,非要用二分求這個r)
【程式碼】
/****
***author: winter2121
****/
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define read(i) scanf("%d",&i)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAX=1e6+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
struct point{
double x,y;
}p[MAX];
int n;
long double calcu(long double x) //求最小圓半徑
{
long double r=0;
for(int i=0;i<n;i++)
{
r=max(r,(x-p[i].x)*(x-p[i].x)/p[i].y/2+p[i].y/2);
}
return r;
}
int main()
{
read(n);
int flag=0;
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
if(p[i].y>0)flag|=1;
if(p[i].y<0)flag|=2;
p[i].y=fabs(p[i].y);
}
if(flag==3) return puts("-1"),0;
long double l=-1e7,r=1e7,lx,rx,dx; //列舉圓心
while(r-l>eps)
{
dx=(r-l)/3.0;
lx=l+dx;
rx=r-dx;
if(calcu(lx)-calcu(rx)<0)r=rx;
else l=lx;
}
printf("%.8f\n",(double)calcu(r));
return 0;
}