codevs 1302 小矮人 凸包 解题报告

题目描述 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
#include
#include
#include
#include
#include
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.xint sign(double x) 
{
    if (fabs(x)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;iwhile(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;iscanf("%lf%lf",&p[i].x,&p[i].y);
    int c=ConvexHull();
    for (int i=0;i1]-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))printf("BAD\n");
            else printf("GOOD\n");
        }
    }
    return 0;
}

你可能感兴趣的:(————单个题目———,————计算几何————)