1. 程式人生 > >poj-1228 Grandpa's Estate(判斷凸包是否唯一)

poj-1228 Grandpa's Estate(判斷凸包是否唯一)

Grandpa's Estate
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 12222 Accepted: 3433

Description

Being the only living descendant of his grandfather, Kamran the Believer inherited all of the grandpa's belongings. The most valuable one was a piece of convex polygon shaped farm in the grandpa's birth village. The farm was originally separated from the neighboring farms by a thick rope hooked to some spikes (big nails) placed on the boundary of the polygon. But, when Kamran went to visit his farm, he noticed that the rope and some spikes are missing. Your task is to write a program to help Kamran decide whether the boundary of his farm can be exactly determined only by the remaining spikes.

Input

The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains an integer n (1 <= n <= 1000) which is the number of remaining spikes. Next, there are n lines, one line per spike, each containing a pair of integers which are x and y coordinates of the spike.

Output

There should be one output line per test case containing YES or NO depending on whether the boundary of the farm can be uniquely determined from the input.

Sample Input

1
6 
0 0
1 2
3 4
2 0
2 4 
5 0

Sample Output

NO
題意:這道題的題意相當難懂。 簡單來說就是平面上有很多很多點,我們可以假設這些點的凸包是A。現在給你點集裡面的部分點,並且跟你說這些點的最邊上的點都是屬於原凸包的(也就是說這部分點的凸包上的每一個點都是凸包A上的頂點)  現在問你,這個凸包會不會等於凸包A?

思路:看題意是不是很難懂? 什麼叫唯一的凸包呢? 我們可以這麼理解,對於一個現有凸包B,如果無論往哪裡新增點,它形成的新的凸包A都是原來的凸包B,那麼這個凸包B就是唯一的。(注意有一個條件是凸包B上的所有點必須在凸包A上)

簡單在紙上畫一下我們就能得出一個結論:只要每條邊至少有第三個點,那麼這個凸包就一定是原凸包A。因為如果一條邊有三個點了,你再往裡面加,根據凸包的性質,必然不會改變凸包結構。而如果你往外面加點,又必然取不到中間的點了,就不滿足凸包B上所有點都在凸包A上這個性質了。又或者你往邊上新增一個點,那麼同理可得,也絕對不會改變凸包性質。

所以這道題其實就是讓你求點集形成的凸包上每條邊是不是至少有三個點。 是不是覺得很簡單了?然而網上很多凸包模板是過不了的,剛開始做這道題,我直接複製了自己的凸包模板,然後簡單判斷一下每條邊是不是有三個點,結果就是WA了。 輸出過程後才發現自己的凸包模板不精確,很多多邊形求出來的凸包是錯的! 比如有一條邊是ac,中間有一點b。凸包理應只有ac兩點,卻多了多餘的b點!這就直接導致無法判斷是否每條邊有三個點或三個點以上!  所以自己又改了改原先的模板,試了幾個特殊樣例才得以AC。

程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define eps 1e-8
#define N 1100
struct Node
{
    double x,y;
}p[N],stack[N];
double mulit(Node a,Node b,Node c)
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
double dist(Node a,Node b)
{
    return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
int cmp(Node a,Node b)
{
    if(mulit(p[0],a,b)>0)
        return 1;
    if(mulit(p[0],a,b)==0&&(dist(p[0],a)-dist(p[0],b))<eps)
        return 1;
    return 0;
}
int Graham(int n)
{
    sort(p+1,p+n,cmp);
    stack[0]=p[0];
    stack[1]=p[1];
    stack[2]=p[2];
    int l=3;
    while(l<n&&mulit(stack[0],stack[1],stack[2])==0)
    {
        stack[1]=stack[2];
        stack[2]=p[l++];
    }
    if(l==n)
        return -1;
    int top=2;
    for(int i=l;i<n;i++)
    {
        while(top>=1&&mulit(stack[top-1],p[i],stack[top])>=0)
            top--;
        stack[++top]=p[i];
    }
    return top;
}
int Pointonline(Node a,Node b,Node c)
{
    if(mulit(b,a,c)!=0)
        return 0;
    if(a.x<=max(b.x,c.x)&&a.y<=max(b.y,c.y)&&a.x>=min(b.x,c.x)&&a.y>=min(b.y,c.y))
        return 1;
    return 0;
}
int main()
{
    int T,n;
    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 k=0;
        for(int i=0;i<n;i++)
        {
            if(p[k].y>p[i].y||(p[k].y==p[i].y&&p[k].x>p[i].x))
                k=i;
        }
        swap(p[0],p[k]);
        int top=Graham(n);
        if(top==-1)
        {
            printf("NO\n");
            continue;
        }
        stack[top+1]=stack[0];
        int flag;
        for(int i=0;i<=top;i++)
        {
            flag=0;
            for(int j=0;j<n;j++)
            {
                if(p[j].x==stack[i].x&&p[j].y==stack[i].y)
                    continue;
                if(p[j].x==stack[i+1].x&&p[j].y==stack[i+1].y)
                    continue;
                if(Pointonline(p[j],stack[i],stack[i+1]))
                    flag=1;
            }
            if(!flag)
                {
                    flag=-1;
                    break;
                }
        }
        if(flag==-1)
            printf("NO\n");
        else
            printf("YES\n");
    }
    return 0;
}