Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=4071
【思路】
二分答案。
假想所有点被一个圆包围着,那么题目就是要求这个最小的圆的半径和圆心坐标(在y轴上)。
对圆的半径进行二分,下限为所有点y值的最大值,上限为3e5(为最大距离)。
对于每一个半径,枚举每一个点。以每个点为圆心作圆,则必定在y轴上得到一个区间,求所有区间的交集。
若交集为空,返回错误,否则取其中点为圆心并返回正确。
由于是special judge,二分精度为1e-9即可。
【代码】
#include <iostream>
#include <cmath>
using namespace std;
#define max(a,b) ((a)>=(b)?(a):(b))
const int maxn = 50000;
struct node
{
double x, y;
}pt[maxn+5];
bool set(double &tl, double &tr, double cl, double cr)
{
if (cl>tr || tl>cr) return false;
if (tr>cr) tr = cr;
if (tl<cl) tl = cl;
return true;
}
bool ok(double r, int n, double &p)
{
int i;
double r2 = r*r;
double td, tl, tr;
td = sqrt(r2-pt[0].y*pt[0].y);
tl = pt[0].x - td;
tr = pt[0].x + td;
for (i=1; i<n; i++)
{
td = sqrt(r2-pt[i].y*pt[i].y);
if (!set(tl, tr, pt[i].x-td, pt[i].x+td))
return false;
}
p = (tl+tr)/2;
return true;
}
void solve(int n, double &p, double &d)
{
double low = 0, high = 3e5;
int i;
for (i=0; i<n; i++) low = max(low, fabs(pt[i].y));
double mid;
while(fabs(high-low)>1e-9)
{
mid = (low+high)/2;
if (ok(mid, n, p))
{
d = mid;
high = mid;
}
else low = mid;
}
}
int main()
{
int n;
int i;
double p, d;
while(scanf("%d", &n)!=EOF)
{
if (n==0) break;
for (i=0; i<n; i++) scanf("%lf %lf", &pt[i].x, &pt[i].y);
solve(n, p, d);
printf("%.9lf %.9lf\n", p, d);
}
return 0;
}