地址:http://codeforces.com/contest/1059/problem/D
思路:题目大意为找与x轴相切并且包含所有点的圆的最小半径。
一,对半径r二分,由于圆与x轴相切,圆心(x,y)中y=r,那么只要看x是否存在即可,对于每一个点找其为圆心,半径为r时在y=r直线上的范围,最后看所有的点是否有公共范围即可
二,对圆心(x,y)中x进行三分,x一定在所有点的x范围[l,r]内,并且其半径r的变换曲线是个U型的
Code 1:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long double LD;
struct node{
LD x;
LD y;
};
const int MAX_N=100005;
const LD emp=1e-7;
int n;
node a[MAX_N];
int main()
{
LD ans=0;
scanf("%d",&n);
for(int i=0;i<n;++i)
{
cin>>a[i].x>>a[i].y;
if(a[i].y>0) ++ans;
else a[i].y=-a[i].y;
}
if(ans&&ans!=n) ans=-1;
LD L=0,R=1e18+5,H;
LD h,l,r,li,ri,t;
while(R-L>emp&&ans!=-1){
h=(L+R)/2;
l=-1e7; r=1e7;
bool boo=true;
for(int i=0;i<n;++i)
{
if(h<a[i].y-h){
boo=false; break;
}
// t=sqrt(h*h-(a[i].y-h)*(a[i].y-h)); //这样写精度不够。。
t=sqrt(h+h-a[i].y)*sqrt(a[i].y);
li=a[i].x-t; ri=a[i].x+t;
l=max(l,li); r=min(r,ri);
if(l>r){
boo=false; break;
}
}
if(boo) R=h;
else L=h;
}
if(ans!=-1){
ans=L;
printf("%.10Lf\n",ans);
}else printf("-1\n");
return 0;
}
Code 2:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long double LD;
struct node{
LD x;
LD y;
};
const int MAX_N=100005;
const LD eps=1e-7;
int n;
node a[MAX_N];
LD judge(LD x){
LD r=0,tmp;
for(int i=0;i<n;++i)
{
tmp=((x-a[i].x)*(x-a[i].x)+a[i].y*a[i].y)/(2.0*a[i].y);
r=max(r,tmp);
}
return r;
}
int main()
{
LD ans=0;
scanf("%d",&n);
for(int i=0;i<n;++i)
{
scanf("%Lf%Lf",&a[i].x,&a[i].y);
if(a[i].y>0) ++ans;
else a[i].y=-a[i].y;
}
if(ans&&ans!=n) ans=-1;
LD l=-1e8,r=1e8,t1,t2;
int ss=100;
while(ss--&&ans!=-1){
t1=l+(r-l)/3; t2=r-(r-l)/3;
if(judge(t1)<=judge(t2)) r=t2;
else l=t1;
}
if(ans!=-1){
ans=judge(l);
printf("%Lf\n",ans);
}else printf("-1\n");
return 0;
}