1. 程式人生 > >poj 1228 Grandpa's Estate (穩定凸包)

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;
}