poj 1228 Grandpa's Estate (稳定凸包)

题目链接:poj 1288

题意:给出n个原来凸包的点,问能否根据这n个点推测出原来的凸包,若能,输出YES

题解:我们先求出这n个点的凸包来,然后在判断新凸包每条边都有其它点在,那么可以说明此边是确定边,因为要想让一个凸包稳定,当且仅当凸包上任意一条边有3个以上的木桩(包括端点)

例如这图,假设新凸包点为A,C,D,很容易可以看到CD边没有其它点,那么这条边就是不确定的,它有可能还有个F点(这个点未知)。

还注意一点的是: 小于6个点,一定不能成稳定凸包,因为最小是三角形的凸包,每条边之间有一个点,那么这都有六个点了。

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>

using namespace std;

const int maxn=1010;

struct point{
    int x,y;
    point(){}
    point(int _x,int _y){
        x=_x;y=_y;
    }
}p[maxn],ch[maxn];

int 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,int p) { return point(a.x*p,a.y*p);}
point operator / (point a,int 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);
}

const double esp=1e-8;
int dcmp(double x)
{
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}

bool operator == (const point &a,const point b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}

int Cross(point a,point b) { return a.x*b.y-a.y*b.x;}
int Dot(point a,point b) { return a.x*b.x+a.y*b.y;}

bool cmp(point a,point b){
    return (a.y<b.y||(a.y==b.y&&a.x<b.x));
}

int tot;
void andrew(int n)
{
    sort(p,p+n,cmp);

    tot=-1;

    for(int i=0;i<n;i++)
    {
        while(tot>0&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot])<=0)
            tot--;
        ch[++tot]=p[i];
    }

    for(int i=n-2,k=tot;i>=0;i--)
    {
        while(tot>k&&Cross(ch[tot]-ch[tot-1],p[i]-ch[tot-1])<=0)
            tot--;
        ch[++tot]=p[i];
    }
}

///判断点在线段上(不包括端点)
bool Onsegment(point p,point a1,point a2)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}

bool judge(point a,point b) ///判断ab边是否稳定
{
    for(int i=0;i<n;i++){
        if(Onsegment(p[i],a,b)) return true;
    }
    return false;
}


int main()
{

    int ncase;
    scanf("%d",&ncase);

    while(ncase--)
    {

        scanf("%d",&n);

        for(int i=0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].y);
        
        if(n<6){ ///小于6个点,一定不能组成稳定的凸包
            puts("NO");continue;
        }

        andrew(n); ///根据这n个点构造凸包


        bool flag=true;

        for(int i=1;i<=tot&&flag;i++)
        {
            if(!judge(ch[i],ch[i-1])){ ///判断ch[i]ch[i-1]这条边是否稳定
                flag=false;break;
            }
        }


        if(flag) puts("YES");
        else puts("NO");
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值