poj Grandpa's Estate

题意:爷爷的农场是一个用大钉打点确定凸包,但是有些大钉不见了, 输入现存的N个刚好构成凸包的点, 求这些点能否唯一确定一个凸包。
分析:1.如果凸包边上至少含有一点, 则凸包可以唯一确定, 因为在凸包边上的外围加上一个点, 则凸包会多出一个不在凸包上的点。
   2. 如果点都共线, 则外围凸包上可以随便放一个或多个点, 凸包不确定。


#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <complex>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <string>
#define INF 1e8
#define MAX (int)1e6+ 5
#define eps 1e-8
using namespace std;
int T, n;
inline int next(const int &i, const int &n){ return (i + 1) % n;}
inline int cmpd(double x){ return x > eps ? 1: (x < -eps? -1 : 0 );}
struct Point{
    int x, y;
    Point (){}
    Point (const int &xx, const int &yy):x(xx),y(yy){}
    friend int det(const Point &a, const Point &b){
        return a.x * b.y - a.y * b.x;
    }
    friend int dot(const Point &a, const Point &b){
        return a.x * b.x + a.y * b.y;
    }
    Point operator - (const Point &a)const{
        return Point(x - a.x, y - a.y);
    }
    bool operator == (const Point &a)const {
        return a.x == x && a.y == y;
    }
    bool operator < (const Point &a)const {
        return x < a.x || ( x == a.x && y < a.y);
    }
    void in(){
        cin>>x>>y;
    }
    void out(){
        cout<<x<<y<<endl;
    }
};
struct Line{
    Point s, t;
    Line(const Point &ss, const Point &tt):s(ss), t(tt){}
    bool isInLineEx(const Point &p){
        int res1 = det(p - s, p - t);///共线
        int res2 = dot(p - s, p - t);///不在两端
        return res1 == 0 && res2 <  0;
    }
};
struct Polygon{
    vector<Point> p;
    Polygon(){}
    Polygon(const vector<Point> &ip):p(ip){}
    double area(){
        int n = p.size();
        double ans = 0;
        for(int i  = 0; i < n; i++){
            ans += det(p[i], p[next(i, n)]);
        }
        ans /= 2.0;
        return ans;
    }
    bool hull(vector<Point> &t){
        int n = t.size(), m = 0;
        p.resize(n);
        sort(t.begin(), t.end());
        t.erase(unique(t.begin(), t.end()), t.end());//去重复
        n = t.size();

        bool isThree = false;
        for(int i = 0; i < n ;i++){
            while( m > 1 && det(p[m - 1] - p[m - 2], p[m - 1] - t[i]) <= 0 )m--;//replaced
            p[m++] = t[i];
        }
        int k = m;
        for(int  i = n - 2; i >= 0; i--){
            while(m > k && det(p[m - 1] -  p[m - 2], p[m - 1] -  t[i]) <= 0)m--;
            p[m++] = t[i];
        }
        p.resize(m);/// 0 - (m - 1) - 0
//        for(int i = 0; i < m - 1; i++){
//            p[i].out();
//        }
        if(cmpd(area()) == 0){return false;}
        for(int i = 0; i < m - 1; i++){
            bool isFind = false;
            Line line(p[i], p[i + 1]);
            for(int j = 0; j < n; j++){
                if(line.isInLineEx(t[j]) ){
                    isFind = true;
                    break;
                }
            }if(!isFind){return false;}
        }
        return true;
    }
};
int main()
{
    cin>>T;
    while(T--){
        cin>>n;
        vector<Point>temp;
        Point t;
        for(int i = 0; i < n; i++){
            t.in(); temp.push_back(t);
        }
        Polygon pg;
        if(pg.hull(temp))puts("YES");
        else puts("NO");

    }
    return 0;
}
/*
5
6
0 0
0 1
0 2
1 0
2 0
1 1
*/


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值