水平序和极角序都可以,极角序相对方便
用极角序的,直接二分就可以了。
#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; }