题目描述 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
解题报告
这道题的题意是给我们n个点,依次给m每个边,问这n个点是否在这条边的同一侧。
我们很容易想到,要把这n个点看做一个整体,最好的办法莫过于搞一个凸包把这n个囊括其中。然后判断这条直线是否穿过这个凸包。
怎样判定直线是否穿过凸包呢?如果一条直线穿过这个凸包,这条直线一定在凸包两个最远点的中间(向量叉乘小于零)。怎样找最远点呢?
二分查找第一个大于直线斜率的边,它的起点一定是一个最远点,因为他后面的边斜率比它大,也就相当于走的离凸包中心越来越近。然后把斜率取相反数,再找第一个斜率大于它的边,起点是另一个最远点。
代码如下:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define NAME ""
#define Point Vector
using namespace std;
const double eps=1e-8;
const double PI=acos(double(-1));
const int N=100000;
struct Vector
{
double x,y;
double len(){return sqrt(x*x+y*y);}
double ang(){double ret=atan2(y,x);return ret<-PI/2?ret+2*PI:ret;}
Vector(int a=.0,int b=.0):x(a),y(b){}
Vector operator+(const Vector &s)const{return Vector(x+s.x,y+s.y);}
Vector operator-(const Vector &s)const{return Vector(x-s.x,y-s.y);}
Vector operator*(int s)const{return Vector(x*s,y*s);}
Vector operator/(int s)const{return Vector(x/s,y/s);}
bool operator<(const Point &s)const
{
if(s.x==x)return y<s.y;
else return x<s.x;
}
}p[N+5],ch[N+5];
int n;
double ang[N+5];
double cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}//向量叉积
int sign(double a){return a>eps?1:(a<-eps?-1:0);}
bool cmp(double a,double b){return sign(b-a)==1;}
bool onleft(Point a,Point b,Point p)
{
return sign(cross(b-a,p-a))>0;
}
int ComvexHull()
{
sort(p+1,p+n+1);
int m=0;
for(int i=1;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-1;i>=1;--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=1;i<=n;i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
p[i]=Point(x,y);
}
int m=ComvexHull();
for(int i=0;i<m;i++)ang[i]=(ch[i+1]-ch[i]).ang();
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+m,(B-A).ang(),cmp)-ang];
Point v=ch[upper_bound(ang,ang+m,(A-B).ang(),cmp)-ang];
if(sign(cross(B-A,u-A)*cross(B-A,v-A))<eps)printf("BAD\n");
else printf("GOOD\n");
}
}
return 0;
}