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;
}

 

posted @ 2013-09-13 22:22  冰鸮  阅读(300)  评论(0编辑  收藏  举报