POJ 1228 Grandpa‘s Estate(稳定凸包)

POJ 1228 Grandpa’s Estate(稳定凸包)

思路:是这样的,题目给你一大堆凸包的点,问你能不能唯一确定一个凸包(稳定凸包)。

稳定凸包:每一条边上起码三个点。

在构建凸包的时候要注意,先确定最下角的点,再进行极角排序然后构建,这样子方便后续判断三点共线。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
double maxx = -1e18;
struct Point
{
    double x, y;
    Point(double x = 0, double y = 0):x(x),y(y) {}
};
typedef Point Vector;
Vector operator + (Vector A, Vector B)
{
    return Vector(A.x+B.x, A.y+B.y);
}
Vector operator - (Point A, Point B)
{
    return Vector(A.x-B.x, A.y-B.y);
}
Vector operator * (Vector A, double p)
{
    return Vector(A.x*p, A.y*p);
}
Vector operator / (Vector A, double p)
{
    return Vector(A.x/p, A.y/p);
}
bool operator < (const Point& a, const Point& b)
{
    if(a.x == b.x)
        return a.y < b.y;
    return a.x < b.x;
}
const double eps = 1e-16;
int sgn(double x)
{
    if(fabs(x) < eps)
        return 0;
    if(x < 0)
        return -1;
    return 1;
}
bool operator == (const Point& a, const Point& b)
{
    if(sgn(a.x-b.x) == 0 && sgn(a.y-b.y) == 0)
        return true;
    return false;
}
double Dot(Vector A, Vector B)
{
    return A.x*B.x + A.y*B.y;
}
double Length(Vector A)
{
    return sqrt(Dot(A, A));
}
double Angle(Vector A, Vector B)
{
    return acos(Dot(A, B)/Length(A)/Length(B));
}
double Cross(Vector A, Vector B)
{
    return A.x*B.y-A.y*B.x;
}
double Area2(Point A, Point B, Point C)
{
    return Cross(B-A, C-A);
}
Vector Rotate(Vector A, double rad) //rad为弧度 且为逆时针旋转的角
{
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A) //向量A左转90°的单位法向量
{
    double L = Length(A);
    return Vector(-A.y/L, A.x/L);
}
double ToLeftTest(Point a, Point b, Point c)
{
    return Cross(b - a, c - a) ;
}

struct Line
{
    Point v, p;
    Line() {}
    Line(Point v, Point p):v(v), p(p) {}
    Point point(double t)
    {
        return v+(p-v)*t;//返回点P = v + (p - v)*t
    }
};


Point GetLineIntersection(Point P, Vector v, Point Q, Vector w)
{
    Vector u = P-Q;
    double t = Cross(w, u)/Cross(v, w);
    return P+v*t;
}

bool LineIntersection(Point a, Point b, Point c, Point d) //直线ab与线段cd相交
{
    return sgn(Cross(b - a, c - a)) *sgn( Cross(b - a, d - a)) <=0;
}


double DistanceToLine(Point P, Point A, Point B)
{
    Vector v1 = B-A, v2 = P-A;
    return fabs(Cross(v1, v2)/Length(v1));
}
Point c;

bool cmp2(Point a,Point b)
{


    if(Cross(b-a,c-a)==0)//计算叉积,函数在上面有介绍,如果叉积相等,按照X从小到大排序
        return a.x<b.x;
    else return Cross(b-a,c-a)>0;
}
int top;
void Convex(Point *p,int N, Point *ch)     //凸包的构建  Andrew算法
{
    for(int i = 1; i < N; i++)     //先按x,y坐标排序,找到原点
    {
        Point temp;
        if(p[i].y < p[0].y || ( p[i].y == p[0].y && p[i].x < p[0].x))
        {
            temp = p[i];
            p[i] = p[0];
            p[0] = temp;
        }
    }
    c = p[0];
    sort(p + 1, p+N  ,  cmp2);  //再将除原点以外的点按极角排序
    ch[0] = p[0];         //先将起始的两个点压入栈内,在进行后面的判断
    ch[1] = p[1];
    top = 1;
    for(int i = 2; i < N; i++)
    {
        while(top >= 1 && Cross(ch[top]-ch[top - 1], p[i]-ch[top - 1]) < 0)top--;         //共线的点也压入凸包内;
        top++;
        ch[top] = p[i];
    }
}
bool judge(Point *ch, int n)
{
    for(int i =1 ; i<n; i++)
    {
        if(Cross(ch[i-1]-ch[i], ch[i+1]-ch[i])!=0 && Cross(ch[i]-ch[i+1], ch[i+2]-ch[i+1])!=0)
            return false;
    }
    return true;
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        Point p[1050];
        Point ch[1050];
        scanf("%d", &n);
        for(int i = 0; i<n; i++)
            scanf("%lf%lf",&p[i].x, &p[i].y);
        if(n<6)
            {
                printf("NO\n");
                continue;
            }
        Convex(p,n,ch);

        if(judge(ch, top))
            printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值