zoukankan      html  css  js  c++  java
  • A Round Peg in a Ground Hole

    题目大意:首先给一个圆的半径和圆心,然后给一个多边形的所有点(多边形按照顺时针或者逆时针给的),求,这个多边形是否是凸多边形,如果是凸多边形在判断这个圆是否在这个凸多边形内。
     
    分析:判断凸多边形可以使用相邻的三个点叉积判断,因为不知道顺时针还是逆时针,所以叉积如果有有整数和负数,那么一定不是凸多边形(注意允许多多点在一条线段上)。判断圆在凸多边形首先要判断圆心是否在多边形内,如果在多边形内,再次判断圆心到达到变形每条边的最短距离,如果小于半径就是不合法。ps:一道好题,通过这个题学会了不少东西。
     
    代码如下:
    =======================================================================================================================================
    #include<stdio.h>
    #include<math.h>
    #include<algorithm>
    using namespace std;
    
    const int MAXN = 1e3+7;
    const double EPS = 1e-8;
    const double oo = 1e10+7;
    
    struct Point
    {
        double x, y;
        Point(double x=0, double y=0):x(x),y(y){}
        Point operator - (const Point &tmp)const{
            return Point(x-tmp.x, y-tmp.y);
        }
        double operator ^(const Point &tmp)const{
            return x*tmp.y - y*tmp.x;
        }
        double operator *(const Point &tmp)const{
            return x*tmp.x + y*tmp.y;
        }
    };
    double Dist(Point a, Point b)
    {///两点间的距离
        return sqrt((a-b)*(a-b));
    }
    int Sign(double t)
    {
        if(t > EPS)return 1;
        if(fabs(t) < EPS)return 0;
        return -1;///负数
    }
    struct Segment
    {
        Point S, E;
        Segment(Point S=0, Point E=0):S(S), E(E){}
        bool OnSeg(const Point &p)
        {///点是否在线段上
            if(Sign( (S-E)^(p-E) ) == 0)///共线
            if(Sign( (p.x-S.x)*(p.x-E.x) ) <= 0)///位于线段的中间或者端点
            if(Sign( (p.y-S.y)*(p.y-E.y) ) <= 0)
                return true;
            return false;
        }
        bool Inter(const Segment &tmp)
        {///只考虑完全相交的情况
            return Sign((S-E)^(tmp.S-E)) * Sign((S-E)^(tmp.E-E)) == -1;
        }
        Point NearPoint(const Point &p)
        {///点到线段最近的点
            Point res;
            double r = ((E-S)*(p-S)) / ((E-S)*(E-S));
    
            if(r > EPS && (1.0 - r) > EPS )
            {///点在线段的投影在线段上
                res.x = S.x + r * (E.x-S.x);
                res.y = S.y + r * (E.y-S.y);
            }
            else
            {///求离最近的端点
                if(Dist(p, S) < Dist(p, E))
                    res = S;
                else
                    res = E;
            }
    
            return res;
        }
    };
    struct Poly
    {
        int N;
        Point vertex[MAXN];
    
        bool IsConvex()
        {///判断是否是凸多边形,可以共线
            int vis[3] = {0};
            for(int i=0; i<N; i++)
            {///如果同时出现整数和负数,说明存在凹的
                int k = Sign((vertex[(i+1)%N]-vertex[i])^(vertex[(i+2)%N]-vertex[i]));
                vis[k+1] = 1;
    
                if(vis[0] && vis[2])
                    return false;
            }
            return true;
        }
        int InPoly(const Point &Q)
        {///判断点Q是否在多边形内,射线法,奇数在内,偶数在外
        ///在圆上返回0, 圆外-1, 圆内 1
            Segment ray(Point(-oo, Q.y), Q);///构造射线的最远处
            int cnt=0;///统计相交的边数
    
            for(int i=0; i<N; i++)
            {
                Segment edge(vertex[i], vertex[(i+1)%N]);
    
                if(edge.OnSeg(Q) == true)
                    return 0;///点在边上
    
                if(ray.OnSeg(vertex[i]) == true)
                {///如果相交连接点,那么取y值小的点
                    if(vertex[(i+1)%N].y - vertex[i].y > EPS)
                        cnt++;
                }
                else if(ray.OnSeg(vertex[(i+1)%N]) == true)
                {
                    if(vertex[i].y - vertex[(i+1)%N].y > EPS)
                        cnt++;
                }
                else if(ray.Inter(edge) && edge.Inter(ray))
                    cnt++;
            }
    
            if(cnt % 2)
                return 1;
            else
                return -1;
        }
    };
    struct Circle
    {
        Point center;///圆心
        double R;///半径
    };
    
    bool Find(Poly &a, Circle &c)
    {///判断圆是否在多边形内
        if(a.InPoly(c.center) == -1)
            return false;///如果圆心在多边形外面
    
        for(int i=0; i<a.N; i++)
        {
            Segment edge(a.vertex[i], a.vertex[(i+1)%a.N]);
            double len = Dist(c.center, edge.NearPoint(c.center));
    
            if(Sign(len-c.R) < 0)
                return false;
        }
    
        return true;
    }
    
    int main()
    {
        Poly a;///定义多边形
        Circle c;///定义圆
    
        while(scanf("%d", &a.N) != EOF && a.N > 2)
        {
            scanf("%lf%lf%lf", &c.R, &c.center.x, &c.center.y);
            for(int i=0; i<a.N; i++)
                scanf("%lf%lf", &a.vertex[i].x, &a.vertex[i].y);
    
            if(a.IsConvex() == false)
                printf("HOLE IS ILL-FORMED
    ");
            else if(Find(a, c) == false)
                printf("PEG WILL NOT FIT
    ");
            else
                printf("PEG WILL FIT
    ");
        }
    
        return 0;
    }
  • 相关阅读:
    WebApi-JSON序列化循环引用
    Android ImageSwitcher
    Android Gallery
    理解URI
    WebApi入门
    URL的组成
    Http协议
    python __new__和__init__的区别
    11.6
    win7 32位用pyinstaller打包Python和相关html文件 成exe
  • 原文地址:https://www.cnblogs.com/liuxin13/p/4799667.html
Copyright © 2011-2022 走看看