poj 1228 Grandpa's Estate 给定了一个凸包的部分顶点和边上的点,判断是否能唯一确定一个凸包

题目来源: 

http://poj.org/problem?id=1228

题意:题目输入一个凸包上的点(没有凸包内部的点,要么是凸包顶点,要么是凸包边上的点),判断这个凸包是否唯一。所谓唯一就是判断能不能在原有凸包上加点,

 得到一个更大的凸包,并且这个凸包包含原有凸包上的所有点。很容易得到,当一个凸包唯一时,凸包的每条边上都要有至少三个点,若只有两个点,则可以增加一个点,得到更大的凸包。

思路:直接求凸包,得到原来凸包顶点,去掉凸包边上的点,由于用graham求凸包的过程中要对点集List[]极角排序,最后只需判断求得的凸包上的点stack[]  本来在 原点集List[]按极角排序后的位置是否相邻,由于凸包的性质,需要特别判断 凸包中第一个和最后一个点 它们之间是否有点。 另外, 若求得凸包中的点个数为2,则输入的所有点都在一条线上,这时需输出NO。

代码如下:

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <stack>
#include <string>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <set>
#include <math.h>
#include <cmath>
#include <map>
#include <queue>
using namespace std ;
typedef long long LL;
const int N = 1010;
double EPS= 1e-10;
double add(double a, double b)
{
    if( fabs(a+b)< EPS * ( fabs(a)+fabs(b) ) )  return 0;
    return a+b;
}
struct Point{
    double x,y;
    Point(){}
    Point(double _x, double _y):x(_x),y(_y){}
    Point operator + (Point p){
        return Point( add(x,p.x), add( y,p.y ) );
    }
    Point operator -(Point p){
        return Point( add(x,-p.x), add(y, -p.y) );
    }
    double operator^(Point p){
        return add(x*p.y, -y*p.x );
    }
    friend istream& operator>>(istream& is, Point& p){
        is>>p.x>>p.y;
        return is;
    }
    double dist(Point p){
        return sqrt( add( ( x-p.x)*(x-p.x) , (y-p.y)*(y-p.y) ) );
    }
};
Point List[N]; // 点集
int top;  // 栈顶指针
int state[N]; // 栈中放的凸包点 原本 在点集按极角排序后的点集合中的位置(指针)
bool cmp(Point a, Point b) // 按y轴值从小到大, y轴值相同时,x轴从小到大排列
{
    if(a.y != b.y) return a.y < b.y;
    else  return a.x < b.x;
}
bool operator < (Point a, Point b) // 极角排序
{
    double tmp= (a-List[0])^(b-List[0]);
    if(tmp > 0) return 1;
    else if(tmp== 0 && a.dist(List[0]) <b.dist(List[0])  ) return 1;
    return 0;
}
void init(int n)
{
    for(int i=0 ; i<n ;i++)
        cin>>List[i];
    sort(List, List+n,cmp);// 排序后 List[0]为最左下方的点
    sort(List+1 , List+n ); // 对List[1,n-1] 中的点进行极角排序,为凸包做准备
}
void graham(int n)
{
   state[0]=0;
   state[1]=1;
   top=1;
   double t;
    for(int i=2 ; i< n ; i++){
        while(top >= 1 && ( (List[state[top] ]-List[ state[top-1] ] )^(List[i]-List[ state[top-1]] ) ) <=0 )
            top--; // 不是凸包中的点出栈
        top++;// 点i进栈
        state[top]=i; // 记录点i进栈的 原本位置 i
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        memset(state,-1,sizeof(state));
        cin>>n;
        init(n);
        graham(n);
        if(top==1)
        {
            printf("NO
");
            continue;
        }
        int i;
        int flag=0;
        for( i=1; i<= top; i++) // 判断凸包顶点【0-1-2-...-top】是否相邻
        {
            if( (state[i-1] +1) == state[i]  ){
                flag=1;
                break;
            }
        }
        for(i=1 ; i<n-1 ; i++) // 判断 凸包中最后一个顶点和 第一个顶点是否相邻
        {
            if( ((List[n-1]-List[0])^(List[i]-List[0])) == 0 )
                break;
        }
        if(i <n-1 && !flag ) printf("YES
");
        else printf("NO
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zn505119020/p/3644088.html