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\n", 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\n", 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\n", 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\n", u, v );

                sanjiao[1] = Poly[u];

                sanjiao[2] = Poly[v];

                if ( check( p, sanjiao ) )

                {

                    ++ans;

                    break;

                }

            }

        }

        printf( "%d\n", ans );

    }

    return 0;

}

 

你可能感兴趣的:(poj)