zoukankan      html  css  js  c++  java
  • SPOJ 149 FSHEEP Fencing in the Sheep ( 计算几何 + 二分 )

    以下摘自SPOJ泛做表格:

    题意:给定一个星形多边形,而且给出了一个可以看到形内所有点的位置(我们称这个点为观察点),让你判断有多少个点位于多边形内。 

    时间复杂度:O(mlogn)

    将多边形上的点按极角排序,观察点与多边形上任意相邻两点形成若干个三角形,再按照极角查找给定点可能位于哪个三角形,最后用叉积判断它是否真的在那个三角形内。

    注意细节,给几组数据:

    input

    8
    4 1
    2 2
    -2 2
    2 -2
    -2 -2
    3 3
    
    6 6
    2 2
    4 4
    6 6
    -3 1
    -1 -1
    5 1
    5 1
    2 2
    6 6
    7 7
    1 1
    3 3
    
    22 15
    2 0
    2 2
    4 4
    5 5
    1 5
    0 5
    -1 5
    -5 5
    -4 4
    -3 3
    -2 2
    -2 0
    -2 -2
    -3 -3
    -4 -4
    -5 -5
    -3 -5
    0 -5
    2 -5
    5 -5
    4 -4
    2 -2
    0 0
    3 3
    3 -3
    1 -5
    0 3
    1 0
    -1 -1
    1 -1
    0 -3
    -1 4
    6 6
    -7 7
    3 0
    -8 2
    0 -8
    
    6 3
    6 6
    4 4
    2 2
    -3 1
    -1 -1
    5 1
    1 1
    6 6
    4 2
    
    3 2
    0 0
    -2 3
    -2 -3
    -1 0
    1 1
    
    5 3
    0 0
    -2 2
    -2 0
    -4 0
    -2 -2
    -3 0
    -2 -1
    -3 1
    
    5 3
    0 0
    -2 2
    -2 0
    -4 0
    -2 -2
    -3 1
    -3 -1
    -3 3
    
    6 5
    6 6
    4 4
    2 2
    -3 1
    -1 -1
    5 1
    2 1
    3 2
    6 6
    3 3
    -3 0

    output

    0
    5
    10
    3
    1
    2
    1
    4
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    const double eps = 1e-8;
    const double PI = acos( -1.0 );
    const int MAXN = 100100;
    
    int dcmp( double x )    //控制精度
    {
        if ( fabs(x) < eps ) return 0;
        else return x < 0 ? -1 : 1;
    }
    
    struct Point
    {
        double x, y;
        double ang;      //极角
        int id;
        Point( double x = 0, double y = 0 ):x(x), y(y) { }
        void readPoint()
        {
            scanf("%lf%lf", &x, &y );
            return;
        }
        void GetAngle()
        {
            ang = atan2( y, x );
            if ( dcmp( ang ) < 0 ) ang = PI + PI+ ang;
            return;
        }
        void showP()
        {
            printf( "(%.6f, %.6f): ang=%.6f id=%d
    ", x, y, ang, id );
            return;
        }
    };
    
    typedef Point Vector;
    
    Vector operator+( Vector A, Vector B )       //向量加
    {
        return Vector( A.x + B.x, A.y + B.y );
    }
    
    Vector operator-( Vector A, Vector B )       //向量减
    {
        return Vector( A.x - B.x, A.y - B.y );
    }
    
    Vector operator*( Vector A, double p )      //向量数乘
    {
        return Vector( A.x * p, A.y * p );
    }
    
    Vector operator/( Vector A, double p )      //向量数除
    {
        return Vector( A.x / p, A.y / p );
    }
    
    bool operator<( const Point& A, const Point& B )   //两点比较小于
    {
        return dcmp( A.x - B.x) < 0 || ( dcmp(A.x - B.x ) == 0 && dcmp( A.y - B.y ) < 0 );
    }
    
    bool operator>( const Point& A, const Point& B )   //两点比较大于
    {
        return dcmp( A.x - B.x) > 0 || ( dcmp(A.x - B.x ) == 0 && dcmp( A.y - B.y ) > 0 );
    }
    
    bool operator==( const Point& a, const Point& b )   //两点相等
    {
        return dcmp( a.x - b.x ) == 0 && dcmp( a.y - b.y ) == 0;
    }
    
    double Dot( Vector A, Vector B )    //向量点乘
    {
        return A.x * B.x + A.y * B.y;
    }
    
    double Length( Vector A )           //向量模
    {
        return sqrt( Dot( A, A ) );
    }
    
    double Angle( Vector A, Vector B )    //向量夹角
    {
        return acos( Dot(A, B) / Length(A) / Length(B) );
    }
    
    double Cross( Vector A, Vector B )   //向量叉积
    {
        return A.x * B.y - A.y * B.x;
    }
    
    bool OnSegment( Point p, Point a1, Point a2 )   //点在线段上,不包含端点
    {
        return dcmp( Cross(a1 - p, a2 - p) ) == 0 && dcmp( Dot( a1 - p, a2 - p ) ) < 0;
    }
    
    int N, M;
    Point Poly[MAXN];
    int Dcnt;
    
    //找到第一个大于的
    void BiSearch( double tar, int l, int r, int& u, int& v )
    {
        //printf("%.6f %.6f %.6f
    ", tar, Poly[1].ang, Poly[N].ang );
        if ( dcmp( tar - Poly[1].ang ) <= 0 || dcmp( tar - Poly[N].ang ) >= 0 )
        {
            u = N;
            v = 1;
            return;
        }
        int mid;
        int ans = N;
        while ( l <= r )
        {
            mid = ( l + r ) >> 1;
            if ( dcmp( Poly[mid].ang - tar ) > 0 )
            {
                ans = mid;
                r = mid - 1;
            }
            else l = mid + 1;
        }
        v = ans;
        u = v - 1;
        return;
    }
    
    bool cmp( Point a, Point b )
    {
        if ( dcmp( a.ang - b.ang ) != 0 )
            return dcmp( a.ang - b.ang ) < 0;
        return a.id < b.id;
    }
    
    void init()
    {
        scanf( "%d%d", &N, &M );
        Dcnt = 0;
        for ( int i = 1; i <= N; ++i )
        {
            Poly[i].readPoint();
            Poly[i].GetAngle();
            Poly[i].id = i;
        }
        sort( Poly + 1, Poly + 1 + N, cmp );
        Poly[0] = Poly[N];
        Poly[0].ang -= 2*PI;
        Poly[N+1] = Poly[1];
        Poly[N+1].ang += 2*PI;
        return;
    }
    
    bool check( Point a, Point *p )
    {
        if ( a == p[1] || a == p[2] || a == p[0] ) return true;
        if ( OnSegment( a, p[1], p[2] ) ) return true;
        if ( OnSegment( a, p[0], p[1] ) ) return true;
        if ( OnSegment( a, p[0], p[2] ) ) return true;
        int pre = dcmp( Cross( p[0] - p[2], a - p[2] ) );
        for ( int i = 0; i < 2; ++i )
        {
            int tmp = dcmp( Cross( p[i + 1] - p[i], a - p[i] ) );
            if ( tmp != pre ) return false;
        }
        return true;
    }
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
        //freopen("out.txt", "w", stdout);
        int T;
        scanf( "%d", &T );
        while ( T-- )
        {
            init();
    
            int ans = 0;
            Point sanjiao[5];
            sanjiao[0] = Point(0, 0);
            for ( int i = 0; i < M; ++i )
            {
                Point p;
                p.readPoint();
                p.GetAngle();
                int u, v;
                BiSearch( p.ang, 1, N, u, v );
                sanjiao[1] = Poly[u];
                sanjiao[2] = Poly[v];
                //printf( "u=%d v=%d
    ", u, v );
                if ( check( p, sanjiao ) )
                {
                    ++ans;
                    continue;
                }
                while ( dcmp( Poly[u-1].ang - p.ang ) == 0 && u != v )
                {
                    --u;
                    if ( u == 0 ) u = N;
                    //printf( "**u=%d v=%d
    ", u, v );
                    sanjiao[1] = Poly[u];
                    sanjiao[2] = Poly[v];
                    if ( check( p, sanjiao ) )
                    {
                        ++ans;
                        break;
                    }
                }
            }
            printf( "%d
    ", ans );
        }
        return 0;
    }
  • 相关阅读:
    关于Windows 8 用户使用习惯调查结果
    Silverlight 可能迎来新版本
    项目总结(1)集中处理上下文
    VSS 团队 沟通
    中国程序员的迷茫?中国软件行业的悲哀?
    开始学点System.Net NameSpace的Class拉
    .Net FSO简单小结(简单到不能再简单了)
    DotNet Framework不协调的一面 ??
    几个开源项目配置信息的存储和处理的方式
    我对委托的一点理解,欢迎斧正
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3320440.html
Copyright © 2011-2022 走看看