poj 1584 A Round Peg in a Ground Hole

题意:1.所有的点不能刚好能构成凸包输出:HOLE IS ILL-FORMED
      2.否则如果圆不超出凸包输出:PEG WILL FIT,不然输出:PEG WILL NOT FIT

分析:先判断判断是不是凸包, 是凸包的情况下判断圆是否在凸包内(包括内切)。


判断凸包:获取凸包,如果最后顶点数和凸包顶点数不一样就不是。


判断圆是否在凸包内:判断圆心在凸包内,在则获取圆心到凸包边上的最小值。大于半径则不在。


判断圆心和凸包的关系:1.查看有向面积符号的一致性O(n)。2.二分极角判断O(log(n))。

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<string>
#include <map>
#include <vector>
#include<algorithm>
#include <complex>
#define eps 1e-8
#define INF 1e8
using namespace std;
typedef double TYPE;
inline int sgn(double x){return x < -eps ? -1 : ( x > eps? 1 :  0);}
struct Point
{
    TYPE x, y;
    Point(){}
    Point(const TYPE &xx, const TYPE &yy):x(xx), y(yy){}
    void input(){scanf("%lf %lf", &x, &y);}
    void output(){ printf("%.2f %.2f\n", x, y);}

    Point operator + (const Point &p)const{ return Point(x + p.x, y + p.y);}
    Point operator - (const Point &p)const{return Point(x- p.x, y - p.y);}
    Point operator / (const TYPE &w)const{return Point(x /w, y/w );}
    Point operator * (const TYPE &w)const{ return Point(x * w, y * w);}
    friend Point operator * (const TYPE &w, const Point &p){ return Point(w * p.x, w * p.y);}
    bool operator < (const Point &p)const{ return x < p.x || ( x == p.x && y < p.y);}
    friend double det(const Point &a, const Point &b){ return a.x* b.y - a.y * b.x;}
    friend double dot(const Point &a, const Point &b){return a.x * b.x + a.y* b.y;}

    double norm()const{ return sqrt(x * x + y * y);}
};
struct Line
{
    Point s, t;
    Line(){}
    Line(Point ss, Point tt):s(ss), t(tt){}
    double distPointToLine(const Point &p){
        if(sgn(dot(t - s, p - s)) < 0)return (p - s).norm();
        if(sgn(dot( s - t, p - t)) < 0)return (p - t).norm();
        return (fabs(det(s - p, t - p))/ (s - t).norm());
    }
};
struct Hull
{
    int n;
    vector<Point>v;
    Hull( ){
        v.resize(0);
    }
    void getHull(vector<Point> &ps){
        int tSize = ps.size();
        v.resize(0);
        sort(ps.begin(), ps.end());
        int m = 0;
        for(int i = 0; i < tSize; i++){
            while(m > 1 && sgn(det(v[m - 1] - v[m - 2], ps[i] - v[m - 2])) < 0)m--, v.pop_back();
            v.push_back(ps[i]);
            m++;
        }
        int k = m;
        for(int i = tSize - 2; i >= 0; i--){
            while(m > k && sgn(det(v[m - 1] - v[m - 2], ps[i] - v[m - 2])) < 0 )m--, v.pop_back();
            v.push_back(ps[i]);
            m++;
        }
        v.resize(m);
        if(m > 0)v.resize(m - 1);
//        for(int i = 0;i  < v.size();i ++){
//            v[i].output();
//        }
    }
   bool isContain(const Point &t){      //  16MS过~
        int sign  = 0;
        int tSize = v.size();
        for(int i = 0; i < tSize; i++){
            if(sgn(det(t - v[i], t - v[(i + 1)%tSize])) == 0){ return true;}//边界上
        }

        for(int i = 0; i < tSize; i++){
            int tSign = sgn(det(v[(i + 1)%tSize] - t, v[i] - t));
            if(tSign){
                if(sign){
                    if(sign != tSign)return false;//外面
                }else {
                    sign = tSign;
                }
            }
        }
        return true;//内部
   }
   //二分极角,Olog(n)版本判断点和凸包的位置关系, 0MS过,神奇!
   bool isContainOlogn(Point &t){
        int n =  v.size(), l = 0, r = n;
        Point g = (v[0] + v[n / 3] + v[n * 2/ 3])/3.0;//凸包内部一个点(其中一个三角形的重心);
        while(l + 1< r){
            int mid = (r + l)>> 1;
            int k = sgn(det(v[l] - g, v[mid] - g));
            int res1 = sgn(det(v[l] - g, t - g));
            int res2 = sgn(det(v[mid] - g, t - g));
            if(k > 0){
                 if(res1>= 0 && res2< 0){
                    r = mid;
                 }else {
                    l = mid;
                 }
            }else {
                if(res1 < 0 &&res2 >=0 ){
                    l = mid;
                }else {
                    r = mid;
                }
            }
        }
        r %= n;
        int res = sgn(det(v[r] - t, v[l] - t));
        if(res == -1 || res == 0)return true;
        return false;
   }
}hull;
vector<Point>ps;
Point co;
double r;
int n;

void init(){
        scanf("%lf", &r);
        co.input();
        ps.resize(n);
        for(int i = 0; i < n; i++){
            ps[i].input();
        }
}

void solve(){
    hull.getHull(ps);
    if(ps.size() != hull.v.size()){
        puts("HOLE IS ILL-FORMED");
    }else {
        if(hull.isContainOlogn(co)){
            int tSize = hull.v.size();
            double min_d = INF;
            for(int i = 0;i < tSize; i++){
                Line line(hull.v[i], hull.v[(i+1)%tSize]);
                min_d = min(line.distPointToLine(co), min_d);
            }
            if(sgn(min_d - r) >= 0){
                puts("PEG WILL FIT");
            }else {
                puts("PEG WILL NOT FIT");
            }
        }else {
            puts("PEG WILL NOT FIT");
        }
    }

}
int main()
{
    while(scanf("%d", &n), n > 2){
        init();
        solve();
    }
    return 0 ;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值