CodeVS1302 小矮人 解题报告【计算几何】【凸包】【凸包与直线判交】

来源:互联网 发布:考古知 编辑:程序博客网 时间:2024/05/18 01:00

题目描述 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 Vectorusing 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;}