Tyvj P2053(线段覆盖‘s精度误差&析构函数)

众所周知,精度误差是很坑人的东西

而且有的时候有了eps反而会错(考虑你的条件是严苛还是放宽)


从 0 到  x0 的覆盖中,点的排序就是一例

首先要尽可能以x排序,然后左端点尽量靠右

但是左端点会爆误差……所以先考虑 端点的误差是否可以忽略,如果不行就算相等)


第二处是排序的对象

理论上是从0到x0 不合条件的都被赋0了……

但是 有可能出现 0<x0<a[i].x<a[i+7].x这样的 整条线段不在里面的情况 此时若用max min 那么 会忽略左端点 (我们的本意是让不在区间内的点的区间删了-要删就全删)

故 需考虑·这样的情况


 <-最右边的黄色和青色的


第三处是答案(终极精度误差)   你要让最左端点<eps和最右端点<x0-eps 这里的限制应为严苛(倘若放宽,最左端点为0(前面已经让它∈[0.x0])都不行的话  会出现永远不可能的情况 



#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXX (10000+10)
#define MAXH (100+10)
#define MAXN (2*7+10)
double h,x0,m;
const double eps=1e-10;
bool cmp(const double a,const double b);
bool equal(const double a,const double b)
{
	if (-eps<a-b&&a-b<eps) return 1;
	else return 0;
}
struct node  //表示线段端点 y=1表示左端点 y=-1有端点  
{
	double x,y;
	node():x(0.0),y(0.0){}
	node(double _x,double _y):x(_x),y(_y){}
	friend bool operator<(const node a,const node b){return equal(a.x,b.x)?a.y>b.y:cmp(a.x,b.x);/*(a.y!=b.y)?a.y>b.y:a.x+eps<b.x||a.x-eps<b.x;*/ /* ? */	}
}a[MAXN];
double x[MAXN],r[MAXN];
bool cmp(const double a,const double b)
{
//	cout<<(a-eps<b)<<endl;
	return ((a-eps<b)||(a+eps<b));
}
bool is_ok(double m)
{
	for (int i=1;i<=7;i++)
	{
		if (h<=r[i]+m)
		{
			double dis=sqrt(pow((r[i]+m),2)-pow((h),2));
		//	if (dis<0) cout<<dis<<' ';
			a[i].x=max(0.0,x[i]-dis);a[i+7].x=min(x0,x[i]+dis);			
		//	if (max(0.0,x[i]-dis)>min(x0,x[i]+dis)) cout<<x[i]-dis<<' '<<x[i]+dis;
			
		}
		else a[i].x=a[i+7].x=0;
		if (a[i].x>a[i+7].x) a[i].x=a[i+7].x=0;
		a[i].y=1;a[i+7].y=-1;
	}
//	for (int i=1;i<=14;i++) cout<<a[i].x<<' '<<a[i].y<<endl;
	sort(a+1,a+1+14);
//	for (int i=1;i<=14;i++) cout<<a[i].x<<' '<<a[i].y<<endl;
	
	for (int i=1,j=0;i<14;i++)
	{
		j+=a[i].y;
		if (!j) return 0;
	}
//	if (cmp(0.0,a[1].x)||cmp(a[14].x,x0)) return 0;
	if ((eps<a[1].x)||(a[14].x<x0-eps)) return 0;
	return 1;
}
int main()
{
//	freopen("rainbow.in","r",stdin);
	scanf("%lf%lf",&h,&x0);
	for (int i=1;i<=7;i++) scanf("%lf%lf",&x[i],&r[i]);

//	for (int i=1;i<=7;i++) cout<<r[i]<<' ';

/*	node a=node(3.0,-1.0);
	node b=node(2.0,-1.0);
	cout<<(a<b)<<endl;
*/	
	double l=0.0,r=x0+h+1;
//	cout<<is_ok(60.0);
	while (r-l>eps)
	{
		double m=(l+r)/2;
		if (is_ok(m)) r=m;
		else l=m;
	}
	printf("%.2lf\n",r);

//	while (1);
	return 0;
} 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值