题目描述 Description
矮人们平时有走亲访友的习惯。一天,矮人国要修一条高速公路,矮人们希望他们走亲访友的时候,能够不必穿越高速公路,这样会更安全一些。现在有M个高速公路的修建方案,请你判断这M条高速功能是否能满足矮人们的期望。也就是说给出平面上的N个点(矮人们的住所位置),对于M条直线(高速公路),依次判断这N个点是否在每条直线的同一侧。是输出GOOD,不是输出BAD。
N,M≤100000
输入描述 Input Description
第一行一个整数N,表示矮人的住所数。
接下来N行每行一个坐标代表矮人的住所坐标。
接下来的若干行(到文件结尾)每行4个整数,代表高速公路上的2个点。
所有坐标均在-109到109之间
输出描述 Output Description
对合法的方案输出GOOD,否则输出BAD。
样例输入 Sample Input
4
0.0 0
6.00 -0.001
3.125 4.747
4.747 0.47
5 3 7 0
4 -4.7 7 4.7
4 47 4 94
样例输出 Sample Output
GOOD
BAD
BAD
思路
首先可以想出一个凸包模型来,因为求出所有点的凸包后可以判断直线如果穿过凸包,就一定不满足题意。
问题是怎么判断直线是否穿过凸包呢?
如果直线穿过凸包,就一定在凸包两个最远点的中间,最远点可以通过下面的方法找:首先预处理记录下凸包每个边的斜率,再算出直线的斜率,将斜率从小到大排列,假设直线斜率是正的,二分查找第一个大于直线斜率的边,它的起点一定是一个最远点,可以画图验证一下,因为他后面的边斜率比它大,也就相当于走的离凸包中心越来越近。然后把斜率取相反数,再找第一个斜率大于它的边,起点是另一个最远点。
在实现时直接用atan2()函数计算角度不用算斜率。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
const int N=100000+10;
const double PI=acos(double(-1));
const double eps=1e-8;
int n;
double ang[N];
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y) {}
};
Point p[N],ch[N];
Point operator +(Point A,Point B) {return Point(A.x+B.x,A.y+B.y);}
Point operator -(Point A,Point B) {return Point(A.x-B.x,A.y-B.y);}
Point operator *(Point A,double p) {return Point(A.x*p,A.y*p);}
Point operator /(Point A,double p) {return Point(A.x/p,A.y/p);}
bool operator <(const Point& a,const Point& b)
{return a.x<b.x||(a.x==b.x&&a.y<b.y);}
int sign(double x)
{
if (fabs(x)<eps) return 0;
else if (x<0) return -1;
else return 1;
}
bool sign2(const double& a,const double& b)
{
if (sign(b-a)==1) return 1;
return 0;
}
bool operator ==(const Point& a,const Point& b)
{return sign(a.x-b.x)==0&&sign(a.y-b.y)==0;}
double angle(Point v)
{
double ret=atan2(v.y,v.x);
return ret<-PI/2?ret+2*PI:ret;
}
double Cross(Point A,Point B)
{return A.x*B.y-A.y*B.x;}
int ConvexHull()
{
sort(p,p+n);
int m=0;
for (int i=0;i<n;i++)
{
while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
int k=m;
for (int i=n-2;i>=0;i--)
{
while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
ch[m++]=p[i];
}
if (n>1) m--;
return m;
}
int main()
{
scanf("%d",&n);
for (int i=0;i<n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
int c=ConvexHull();
for (int i=0;i<c;i++)
ang[i]=angle(ch[i+1]-ch[i]);
Point a,b;
while(scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y)==4)
{
if (n<=1) printf("GOOD\n");
else
{
Point u=ch[upper_bound(ang,ang+c,angle(b-a),sign2)-ang];
Point v=ch[upper_bound(ang,ang+c,angle(a-b),sign2)-ang];
if (sign(Cross(b-a,u-a)*Cross(b-a,v-a))<eps)
printf("BAD\n");
else printf("GOOD\n");
}
}
return 0;
}