现在的位置: 首页 > 综合 > 正文

SGU 253 log(n)判点在凸包内 二分

2014年07月19日 ⁄ 综合 ⁄ 共 2011字 ⁄ 字号 评论关闭

水平序和极角序都可以,极角序相对方便

用极角序的,直接二分就可以了。

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

抱歉!评论已关闭.