穿越七色虹

Description

探险队员们跟随两位护法来到了七色虹前。七色虹,就是平面直角坐标系中赤橙黄绿青蓝紫七个半圆,第i座(1<=i<=7)半圆形彩虹的圆心是(xi,0),半径是ri,半圆上所有点的纵坐标均为非负数。探险队员可以看做一条竖直的、长度等于身高的线段,线段的底端纵坐标为0,最高的一位探险队员的身高为h。 
 
现在探险队员们要从(0,0)到达(x0,0),穿越彩虹的过程中,探险队员的整个身体必须始终在至少一个半圆形彩虹的内部。由于彩虹的半径ri可能太小了,不足以满足这个条件,因此两位护法决定帮助他们把所有彩虹的半径都增大一个非负实数r。探险队员们想知道,r最小是多少呢?

Input

第一行两个实数h、x0,表示身高和目的地横坐标。 
接下来七行每行两个实数xi、ri,表示七座半圆形彩虹的圆心和半径。

Output

输出最小的r,四舍五入保留0位小数。

Sample Input

输入样例1:
4.0 36.0
0.0 4.0
6.0 4.0
12.0 4.0
18.0 4.0
24.0 4.0
30.0 4.0
36.0 4.0

输入样例2:
87.20 2955.25
9306.25 379.83
1587.65 881.07
653.83 939.21
3384.39 818.71
8069.61 30.49
306.37 300.35
7695.43 646.25

Sample Output

输出样例1:
1
输出样例2:
53

Hint

对于 100% 满足 0<= xi,x0 <=10000,0<h<100。


【分析】

      其实就是二分答案加验证吧,验证的时候用勾股定理加线段覆盖。


【代码】

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
double h,x0,x[8],r[8],tr[8],tl[8];
void _init()
{
	scanf("%lf%lf",&h,&x0);
	for(int i=1;i<=7;i++)
		scanf("%lf%lf",&x[i],&r[i]);
}
bool _can_match(double Mid)
{
	memset(tl,0,sizeof(tl));
	memset(tr,0,sizeof(tr));
	double ad,R,L;
    for(int i=1;i<=7;i++)       //找出每段线段 
	    if(r[i]+Mid>h)
	    {
		    ad=sqrt((Mid+r[i])*(Mid+r[i])-h*h);
		    tl[i]=x[i]-ad;
		    tr[i]=x[i]+ad;
	    }
    R=0;L=x0;
    for(int i=1;i<=7;i++)     //判断是否覆盖0~x0 
	    if(r[i]+Mid>h)
	    {
		    if(tl[i]<=R&&R<=tr[i])
				R=tr[i];
			if(tl[i]<L)
				L=tl[i];
		}
	if(L<=0&&R>=x0)
		return true;
	return false;
}
void _solve()
{ 
	for(int i=1;i<=7;i++)           //排序 
		for(int j=i+1;j<=7;j++)
			if(x[i]>x[j])
			{
				swap(x[i],x[j]);
				swap(r[i],r[j]);
			}
	double Left=0,Right=1000000.0,Mid,ans=0;     //二分答案 
	bool mark;
	while(Left<=Right)
	{
		Mid=(Left+Right)/2;
		mark=_can_match(Mid);
		if(mark)
		{
			ans=Mid;
			Right=Mid-0.0001;
		}
		else
			Left=Mid+0.0001;
	}
	int temp=0;             //四舍五入 
	ans*=10;
	temp=(int)(ans);
	if(temp%10>=5)
		temp=temp/10+1;
	else
		temp/=10;
	printf("%d\n",temp);
}
int main()
{
	_init();
	_solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值