题目:http://acm.sgu.ru/problem.php?contest=0&problem=253
本题要求在一个给定凸包,一些点有几个是在凸包内的(包括边界)。
以前判断某一点是否在多边形内,可以叉积依次求面积的方法,但是每次查询耗时O(n)。
所以这里提一种每次查询只需要O(lgn)的解法。
就是先按极角排序,然后二分求给定点的极角范围,叉积计算进行求解。
一开始我的线段拐向求反了,导致wa on test 5。一定要小心啊。
而且swap写的一开始也有问题,谢学弟帮我排bug。二分法的临界仍然需要熟练掌握。是在担心写错,就直接用STL upper_bound吧。不要自己写了。
http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
struct Point
{
long long x;
long long y;
double angle;
long long dis;
Point() {}
Point(long long _x,long long _y):x(_x),y(_y) {}
friend Point operator + (Point a,Point b)
{
return Point(a.x+b.x , a.y+b.y);
}
friend Point operator - (Point a,Point b)
{
return Point(a.x-b.x , a.y-b.y);
}
};
int dcmp(double x)
{
if(fabs(x)<eps)
{
return 0;
}
return x>0?1:-1;
}
double det(Point a,Point b)
{
return a.x*b.y-a.y*b.x;
}
double det(Point a,Point b,Point o)
{
return det(a-o,b-o);
}
double det(Point a,Point b,Point c,Point d)
{
return det(b-a,d-c);
}
Point p[100005];
bool cmp(Point a,Point b)
{
return dcmp(a.angle-b.angle)<0 || (dcmp(a.angle - b.angle)==0 && a.dis <b.dis);
}
void swap(Point &a,Point &b)
{
Point c = b;
b = a;
a = c;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int n,m,k;
while(scanf(" %d %d %d",&n,&m,&k)!=EOF)
{
Point le;
int le_num = 0;
for(int i=0;i<n;i++)
{
scanf(" %lld %lld",&p[i].x,&p[i].y);
//求最下左点
if(i==0)
{
le.x = p[0].x;
le.y = p[0].y;
le_num = 0;
}
else
{
if(p[i].y<le.y || (p[i].y == le.y && p[i].x < le.x))
{
le = p[i];
le_num = i;
}
}
}
swap(p[0],p[le_num]);
for(int i=1;i<n;i++)
{
p[i].angle = atan2(p[i].y - p[0].y,p[i].x - p[0].x);
p[i].dis = (p[i].x - p[0].x)*(p[i].x - p[0].x) + (p[i].y - p[0].y)*(p[i].y - p[0].y);
}
sort(p+1,p+n,cmp);
int x,y;
int num = 0;
for(int i=0;i<m;i++)
{
Point temp;
scanf(" %lld %lld",&temp.x,&temp.y);
if(temp.x == p[0].x && temp.y == p[0].y)
{
num++;
}
else
{
temp.angle = atan2(temp.y-p[0].y,temp.x-p[0].x);
int low = 1;
int high = n-1;
if(dcmp(temp.angle - p[high].angle)>0 || dcmp(temp.angle - p[low].angle)<0)
{
continue;
}
int pos = 1;
//求upper_bound
while(low<high)
{
int mid = (low + high)/2;
if( p[mid].angle <= temp.angle)
{
low = mid + 1;
pos = low;
}
else
{
high = mid;
pos = high;
}
}
if(pos == n)
{
pos--;
}
if(det(temp,p[pos -1],p[pos])>=0)
{
num++;
}
}
}
if(num>=k)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}
参考:
http://hi.baidu.com/aekdycoin/item/2d54f9c0fef55457ad00efd6