POJ 1228 Grandpa's Estate

题意:给定一些点,看能否确定唯一的一个凸包。

题解:只有保证凸包上的每条边都至少有三个点时,才能确定其唯一性。否则可以通过在两点构成的边的外围,增加点的来改变凸包。当所有点都在同一条直线上,或者给定的点少于6个时,不能唯一确定凸包。

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using std::memset;
using std::min;

#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)
struct Point { double x, y; };
Point p[2000], p1, p2;

//计算cross product (P1-P0)x(P2-P0)
double xmult(Point p1,Point p2,Point p0)
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

int dots_inline(Point p1,Point p2,Point p3){
	return zero(xmult(p1,p2,p3));
}

// graham算法顺时针构造所有共线点的凸包(n*logn)
int graham_cp ( const void* a, const void* b )
{
    double ret = xmult(*((Point*)a), *((Point*)b), p1);
    if ( ! zero(ret) )
        return ret > 0 ? 1 : -1;
    return xmult(*(Point*)a, *(Point*)b, p2) > 0 ? 1 : -1;
}

void _graham ( int n, Point* p, int &top, Point* stk )
{
    int k = 0, i;
    p1 = p2 = p[0];
    for ( int i = 1; i < n; i++ ) //找到最左下角的点p1; p2用来求平均值点
    {
        if ( p1.y - p[i].y > eps || (zero(p1.y-p[i].y) && p1.x > p[i].x) )
            p1 = p[k=i];
        p2.x += p[i].x; p2.y += p[i].y;
    }

    p2.x /= n; p2.y /= n;
    p[k] = p[0]; p[0] = p1;  //将最左下角的点p1与p[0]交换
    qsort(p+1,n-1,sizeof(Point),graham_cp);

    stk[0] = p[0], stk[1] = p[1], stk[2] = p[2];
    for ( top = i = 3; i < n; i++ )
    {
        while ( top > 2 && xmult(stk[top-2], p[i], stk[top-1] ) < -eps) top--;
        stk[top++] = p[i];
    }
}

int graham ( int n, Point* p, Point* convex, int maxsize = 1, int dir = 1 )
{
    Point *temp = new Point[n];
    int s, i;
    _graham(n,p,s,temp);
    convex[0] = temp[0], n = 1;
    for ( i = (dir ? 1:(s-1)); dir ? (i<s) : i; i += (dir ? 1 : -1))
    {
        if ( maxsize || ! zero(xmult(temp[i-1], temp[i], temp[(i+1)%s])) )
            convex[n++] = temp[i];
    }
    delete [] temp;
    return n;
}

int main()
{
    int t, n;
    Point convex[2000];
    scanf("%d",&t);
    while ( t-- )
    {
        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; }
        int tn = graham(n, p, convex, 1, 1);
        convex[tn] = convex[0];

        bool flag = true;
        bool turn = false;
        int que[1000];
        int front = 0, rear = 0;
        que[rear++] = 0; que[rear++] = 1;
        for ( int i = 2; i <= tn; i++ )
        {
            if ( dots_inline(convex[i],convex[que[front]], convex[que[front+1]]) )
                que[rear++] = i;
            else
            {
                if ( rear - front < 3 ) { flag = false; break; }
                front = rear - 1;
                que[rear++] = i;
                turn = true;
            }
        }

        if ( flag && turn ) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值