Gym 101464C - 计算几何+二分

https://vjudge.net/problem/Gym-101464C

 

We are given N line segments on the 2D plane. We want to find the maximum radius of an empty circle whose center coordinates (xc, yc) are constrained as follows:

  • 0$ \le$xcL
  • yc = 0

A circle is empty if no part of a segment is located strictly inside of it (thus, a segment may touch the circle, but may not intersect with the interior of the circle).

 

Input 

The first line of the input file contains the number of test cases T. The test cases are described next. The first line of a test case contains the integer numbers N and L (1N2000 and0L10000). The next N lines of the test case contain 4 integers each, describing the coordinates of the endpoints of a segment: xa, ya, xb and yb. The coordinates of the endpoints of the segment are (xa, ya) and (xb, yb). All the coordinates are between -20000 and +20000. Every two consecutive numbers on the same line are separated by a single blank.

Output 

For each test case print a line containing a real number R, denoting the maximum radius of an empty circle whose center obeys the constraints. The number must be printed with 3 decimal digits (the number must be rounded up or down according to the usual rounding rules).

 

\epsfbox{p4818.eps}

Sample Input 

1 
4 10 
1 1 10 3 
5 3 9 1 
3 1 4 1 
8 3 11 -3

Sample Output 

2.118

 

题意:

平面上有一些线段,找出圆心在x轴上,x坐标在[0,L]内半径最大的圆,使得圆和任意一条线段不相交,输出最大的半径

分析:

对半径二分,这样我们只需要判断能不能放的下这个圆。这时,通过给定的半径,对于每一条线段可以找到一个区间(或者为空),使得圆心不能落在这个区间上,我们只需要判断区间的并集是否覆盖了[0,L]。那么如何去找到这个区间呢?对于每一个线段,我们可以找到线段上y坐标的绝对值最小的点,这个点一定是线段的端点或者是零点,这是线段到直线的最短距离。如果最短距离小于半径,那么区间为空;如果最短距离大于半径,这个点两边的点到线段都具有单调性,我们对左右两侧分别二分找到距离等于半径的点即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define eps 1e-6
struct point
{
	double x,y;
	point(){}
	point(double _x,double _y)
	{
		x = _x;y = _y;
	}
	point operator -(const point &b)const
	{
		return point(x - b.x,y - b.y);
	};
	double operator ^(const point &b)const
	{
		return x*b.y - y*b.x;
	}
	double operator *(const point &b)const
	{
		return x*b.x + y*b.y;
	}
};
struct line
{
	point s,e;
}c[2005];
int t,n,L;
struct st
{
	double l,r;
};
vector<st> v;

double dist(point a,point b)
{
	return sqrt((a-b)*(a-b));
}

point NearestPointToLineSeg(point P,line L)
{
	point result;
	double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s));
	if(t >= 0 && t <= 1)
	{
		result.x = L.s.x + (L.e.x - L.s.x)*t;
		result.y = L.s.y + (L.e.y - L.s.y)*t;
	}
	else
	{
		if(dist(P,L.s) < dist(P,L.e))
		result = L.s;
		else result = L.e;
	}
	return result;
}

double find2(line L,double rr,double l,double r)
{
	double m;
	while (r-l>1e-6)
	{
		m=(l+r)/2;
		if (dist(NearestPointToLineSeg(point(m,0),L),point(m,0))<rr) r=m;
		else l=m;
	}
	return (l+r)/2;
}

double find3(line L,double rr,double l,double r)
{
	double m;
	while (r-l>1e-6)
	{
		m=(l+r)/2;
		if (dist(NearestPointToLineSeg(point(m,0),L),point(m,0))>rr) r=m;
		else l=m;
	}
	return (l+r)/2;
}

bool cmp(st a,st b)
{
	if (fabs(a.l-b.l)<1e-6) return a.r<b.r;
	else return a.l<b.l;
}

bool ok(double h)
{
	sort(v.begin(),v.end(),cmp);
	if (v.empty()) return false;
	if (v[0].l+eps>0) return false;
	double r=v[0].r;
	int i=0;
	while (i<(int)v.size()-1 && (v[i+1].l+eps<r || v[i+1].l<0))
	{
		i++;
		r=max(r,v[i].r);
	}
	if (r+eps<h) return false;
	else return true;	
}
	

int go(double rr)
{
	v.clear();
	for (int i=1;i<=n;i++)
	{
		double len;
		double mid;
		double l,r;
		if (c[i].s.y*c[i].e.y>0)
		{
			if (fabs(c[i].s.y)>fabs(c[i].e.y))
			{
				len=fabs(c[i].e.y);
				mid=c[i].e.x;
			}
			else
			{
				len=fabs(c[i].s.y);
				mid=c[i].s.x;
			}
		}
		else
		{
			len=0;
			mid=c[i].s.x+fabs((c[i].s.y/(c[i].e.y-c[i].s.y)*(c[i].e.x-c[i].s.x)));
		}
		if (len<rr)
		{
			l=find2(c[i],rr,-3e4,mid);
			r=find3(c[i],rr,mid,3e4);
			st x;
			x.l=l;x.r=r;
			v.push_back(x);
		}
	}
	return !ok(L);
}

double find1()
{
	double l=0,r=2e4;
	double m;
	while (r-l>1e-6)
	{
		m=(l+r)/2;
		if (go(m)==1) l=m;
		else r=m;
	}
	return (l+r)/2;
}

int main()
{
	freopen("c.in","r",stdin);
	scanf("%d",&t);
	while (t--)
	{
		scanf("%d%d",&n,&L);
		for (int i=1;i<=n;i++)
		{
			scanf("%lf%lf%lf%lf",&c[i].s.x,&c[i].s.y,&c[i].e.x,&c[i].e.y);
			if (c[i].s.x>c[i].e.x) swap(c[i].e,c[i].s);
		}
		printf("%.3f\n",find1());
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/njupt_lyy/article/details/81256538
今日推荐