以下摘自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; }