水平序和极角序都可以,极角序相对方便
用极角序的,直接二分就可以了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const int maxn = 100005;
struct Point {
double x, y;
}p[maxn];
int n, m, k;
double cross(Point o, Point a, Point b) {
return (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x);
}
bool binary(Point *p, Point &tp) {
//条件:p点集必须是顺时针或者逆时针
//(注意3点共线下的点也必须满足这个条件)
//(如果有3点共线极角序不能完成该条件)
int l = 0, r = n-1;
while(l < r) {
int m = l+r >> 1;
int c1 = cross(p[0], p[m], tp);
int c2 = cross(p[0], p[(m+1)%n], tp);
int c3 = cross(p[m], p[(m+1)%n], tp);
if(c1 >= 0 && c2 <= 0 && c3 >= 0)
return true;
if(c1 >= 0) l = m+1;
else r = m;
}
return false;
}
int main() {
int i;
scanf("%d%d%d", &n, &m, &k);
for(i = 0; i < n; i++)
scanf("%lf%lf", &p[i].x, &p[i].y);
int cnt = 0;
p[n] = p[0];
while(m--) {
Point tp;
scanf("%lf%lf", &tp.x, &tp.y);
cnt += binary(p, tp);
}
if(cnt >= k) puts("YES");
else puts("NO");
return 0;
}
用水平序做的,我的做法还要对点排序和求上下凸包,
还是写搓了,不想写极角序了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define LL __int64
int n, m, k;
struct point {
int x, y;
void in() {
scanf("%d%d", &x, &y);
}
bool operator < (const point &t) const{
return y < t.y || (y == t.y && x < t.x);
}
bool operator == (const point &t) const {
return x == t.x && y == t.y;
}
}p[100005];
LL cross(point o, point a, point b) {
return (LL)(a.x-o.x)*(b.y-o.y)-(LL)(a.y-o.y)*(b.x-o.x);
}
point up[100005], down[100005]; // 水平序后的上下凸包
int top, sum1, sum2;
void convex() {
top = 0;
int i, j;
for(i = 0; i < n; i++) {
while(top >= 2 && cross(down[top-2], down[top-1], p[i]) < 0) top--;
down[top++] = p[i];
}
sum2 = top;
top = 0;
for(i = n-1; i >= 0; i--) {
while(top >= 2 && cross(up[top-2], up[top-1], p[i]) < 0) top--;
up[top++] = p[i];
}
sum1 = top;
reverse(up, up+sum1); // 为了后面的lower_bound
}
int main() {
int i, j;
scanf("%d%d%d", &n, &m, &k);
for(i = 0; i < n; i++) p[i].in();
sort(p, p+n);
convex();
int cnt = 0;
while(m--) {
point tp;
tp.in();
if(tp == p[0] ) { cnt++; continue; } // 注意最左下角的点要特判
int j = lower_bound(up, up+sum1, tp) - up-1; //找点tp在点j和点j+1之间
if(j >= sum1-1 || j < 0) continue;
bool g1 = cross(up[j], up[j+1], tp) <= 0;
j = lower_bound(down, down+sum2, tp) - down-1; //找点tp在点j和点j+1之间
if(j >= sum2-1 || j < 0) continue;
bool g2 = cross(down[j], down[j+1], tp) >= 0;
if(g1 && g2) cnt++;
}
if(cnt >= k) puts("YES");
else puts("NO");
return 0;
}