HDU4071 Trick or Treat 二分

9 篇文章 0 订阅
4 篇文章 0 订阅

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;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值