POJ - 2318 TOYS

判断点是否在多边形内,射线法O(n)
如果对每个点顺序地判断每个小四边形,算下复杂度O(n*m),显然tle
可以二分优化,注意二分终点是l + 1 < r.


const int maxn = 1e5 + 7;

int u[maxn], l[maxn];

const double eps = 1e-6;
//const double PI = acos(-1);

int n, m;

struct Point {
    double x, y;

    Point(double x = 0, double y = 0) : x(x), y(y) {}

    //向量+
    Point operator+(const Point &b) const {
        return Point(x + b.x, y + b.y);
    }

    //向量-
    Point operator-(const Point &b) const {
        return Point(x - b.x, y - b.y);
    }

    //点积
    double operator*(const Point &b) const {
        return x * b.x + y * b.y;
    }

    //叉积
    //P^Q>0,P在Q的顺时针方向;<0,P在Q的逆时针方向;=0,P,Q共线,可能同向或反向
    double operator^(const Point &b) const {
        return x * b.y - b.x * y;
    }
};

vector<Point> polygon;
//typedef Point Vector;

//三态函数,判断两个double在eps精度下的大小关系
int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    else
        return x < 0 ? -1 : 1;
}

//判断点Q是否在P1和P2的线段上
bool OnSegment(Point P1, Point P2, Point Q) {
    return dcmp((P1 - Q) ^ (P2 - Q)) == 0 && dcmp((P1 - Q) * (P2 - Q)) <= 0;
}

//判断点P在多边形内-射线法
bool InPolygon(Point P) {
    bool flag = false;
    Point P1, P2; //多边形一条边的两个顶点
    int pontnum = polygon.size() - 1;
    for (int i = 0, j = pontnum; i <= pontnum; j = i++) {
        P1 = polygon[i];
        P2 = polygon[j];
        if (OnSegment(P1, P2, P)) return true; //点在多边形一条边上
        if ((dcmp(P1.y - P.y) > 0 != dcmp(P2.y - P.y) > 0) &&
            dcmp(P.x - (P.y - P1.y) * (P1.x - P2.x) / (P1.y - P2.y) - P1.x) < 0)
            flag = !flag;
    }
    return flag;
}

int x1, y1_, x2, y2;
int cnt[maxn];
Point test, pt;

bool check(int l_, int r_) {
    polygon.clear();
    pt.x = u[l_], pt.y = y1_;
    polygon.push_back(pt);
    pt.x = l[l_], pt.y = y2;
    polygon.push_back(pt);
    pt.x = l[r_], pt.y = y2;
    polygon.push_back(pt);
    pt.x = u[r_], pt.y = y1_;
    polygon.push_back(pt);
    return InPolygon(test);
}

int check() {
    int l_ = 0, r = n + 1, mid;
    while (l_ + 1 < r) {
        mid = (l_ + r) / 2;
        if (l_ != mid && check(l_, mid))
            r = mid;
        else
            l_ = mid;
    }
    return l_;
}

void solve() {
    while (scanf("%d%d%d%d%d%d", &n, &m, &x1, &y1_, &x2, &y2) && n != 0) {
        u[0] = x1, l[0] = x1;
        for (int i = 1; i <= n; i++)
            scanf("%d%d", &u[i], &l[i]);
        u[n + 1] = x2, l[n + 1] = x2;
        for (int i = 0; i <= n; i++)
            cnt[i] = 0;
        for (int c = 0; c < m; c++) {
            scanf("%lf%lf", &test.x, &test.y);
            cnt[check()]++;
        }
        for (int i = 0; i <= n; i++)
            printf("%d: %d\n", i, cnt[i]);
        cout << endl;
    }
}

posted @ 2021-03-15 19:11  naymi  阅读(38)  评论(0)    收藏  举报