zoukankan      html  css  js  c++  java
  • POJ 3805 Separate Points (判断凸包相交)

    题目链接:POJ 3805

    Problem Description

    Numbers of black and white points are placed on a plane. Let’s imagine that a straight line of infinite length is drawn on the plane. When the line does not meet any of the points, the line divides these points into two groups. If the division by such a line results in one group consisting only of black points and the other consisting only of white points, we say that theline “separates black and white points”.

    Let’s see examples in Figure 3. In the leftmost example, you can easily find that the black and white points can be perfectly separated by the dashed line according to their colors. In the remaining three examples, there exists no such straight line that gives such a separation.

    title

    In this problem, given a set of points with their colors and positions, you are requested to decide whether there exists a straight line that separates black and white points.

    Input

    The input is a sequence of datasets, each of which is formatted as follows.

      n m 
      x1 y1 
      . 
      . 
      . 
      xn yn 
      xn+1 yn+1 
      . 
      . 
      . 
      xn+m yn+m 
    

    The first line contains two positive integers separated by a single space; n is the number of black points, and m is the number of white points. They are less than or equal to 100. Then n + m lines representing the coordinates of points follow. Each line contains two integers xi and yi separated by a space, where (xi, yi) represents the x-coordinate and the y-coordinate of the i-th point. The color of the i-th point is black for 1 <= i <= n, and is white for n + 1 <= i <= n + m.

    All the points have integral x- and y-coordinate values between 0 and 10000 inclusive. You can also assume that no two points have the same position.

    The end of the input is indicated by a line containing two zeros separated by a space.

    Output

    For each dataset, output “YES” if there exists a line satisfying the condition. If not, output “NO”. In either case, print it in one line for each input dataset.

    Sample Input

    3 3
    100 700
    200 200
    600 600
    500 100
    500 300
    800 500
    3 3
    100 300
    400 600
    400 100
    600 400
    500 900
    300 300
    3 4
    300 300
    500 300
    400 600
    100 100
    200 900
    500 900
    800 100
    1 2
    300 300
    100 100
    500 500
    1 1
    100 100
    200 100
    2 2
    0 0
    500 700
    1000 1400
    1500 2100
    2 2
    0 0
    1000 1000
    1000 0
    0 1000
    3 3
    0 100
    4999 102
    10000 103
    5001 102
    10000 102
    0 101
    3 3
    100 100
    200 100
    100 200
    0 0
    400 0
    0 400
    3 3
    2813 1640
    2583 2892
    2967 1916
    541 3562
    9298 3686
    7443 7921
    0 0
    

    Sample Output

    YES
    NO
    NO
    NO
    YES
    YES
    NO
    NO
    NO
    YES
    

    Solution

    题意

    平面上有一些白点和黑点,问是否存在一条直线能把两类点分开。

    题解

    模板题。

    详见 UVA 10256 The Great Divide (判断凸包相交)

    Code

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const double eps = 1e-8;
    const double pi = acos(-1.0);
    class Point {
    public:
        double x, y;
        Point(double x = 0, double y = 0) : x(x), y(y) {}
        Point operator+(Point a) {
            return Point(a.x + x, a.y + y);
        }
        Point operator-(Point a) {
            return Point(x - a.x, y - a.y);
        }
        bool operator<(const Point &a) const {
            if (x == a.x)
                return y < a.y;
            return x < a.x;
        }
        bool operator==(const Point &a) const {
            if (fabs(x - a.x) < eps && fabs(y - a.y) < eps)
                return 1;
            return 0;
        }
        double length() {
            return sqrt(x * x + y * y);
        }
    };
    
    typedef Point Vector;
    
    double cross(Vector a, Vector b) {
        return a.x * b.y - a.y * b.x;
    }
    
    double dot(Vector a, Vector b) {
        return a.x * b.x + a.y * b.y;
    }
    
    bool isclock(Point p0, Point p1, Point p2) {
        Vector a = p1 - p0;
        Vector b = p2 - p0;
        if (cross(a, b) < -eps)
            return true;
        return false;
    }
    
    double getDistance(Point a, Point b) {
        return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
    }
    
    typedef vector<Point> Polygon;
    Polygon Andrew(Polygon s) {
        Polygon u, l;
        if(s.size() < 3) return s;
        sort(s.begin(), s.end());
        u.push_back(s[0]);
        u.push_back(s[1]);
        l.push_back(s[s.size() - 1]);
        l.push_back(s[s.size() - 2]);
        for(int i = 2 ; i < s.size() ; ++i) {
            for(int n = u.size() ; n >= 2 && !isclock(u[n - 2], u[n - 1], s[i]); --n) {
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        for(int i = s.size() - 3 ; i >= 0 ; --i) {
            for(int n = l.size() ; n >=2 && !isclock(l[n-2],l[n-1],s[i]); --n) {
                l.pop_back();
            }
            l.push_back(s[i]);
        }
        for(int i = 1 ; i < u.size() - 1 ; i++) l.push_back(u[i]);
        return l;
    }
    
    int dcmp(double x)  {
        if (fabs(x) <= eps)
            return 0;
        return x > 0 ? 1 : -1;
    }
    
    // 判断点在线段上
    bool OnSegment(Point p, Point a1, Point a2) {
        return dcmp(cross(a1 - p, a2 - p)) == 0 && dcmp(dot(a1 - p, a2 - p)) < 0;
    }
    
    // 判断线段相交
    bool Intersection(Point a1, Point a2, Point b1, Point b2) {
        double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1),
                c3 = cross(b2 - b1, a1 - b1), c4 = cross(b2 - b1, a2 - b1);
        return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
    }
    
    // 判断点在凸包内
    int isPointInPolygon(Point p, vector<Point> s) {
        int wn = 0, cc = s.size();
        for (int i = 0; i < cc; i++) {
            Point p1 = s[i];
            Point p2 = s[(i + 1) % cc];
            if (p1 == p || p2 == p || OnSegment(p, p1, p2)) return -1;
            int k = dcmp(cross(p2 - p1, p - p1));
            int d1 = dcmp(p1.y - p.y);
            int d2 = dcmp(p2.y - p.y);
            if (k > 0 && d1 <= 0 && d2 > 0) wn++;
            if (k < 0 && d2 <= 0 && d1 > 0) wn--;
        }
        if (wn != 0) return 1;
        return 0;
    }
    
    void solve(Polygon s1, Polygon s2) {
        int c1 = s1.size(), c2 = s2.size();
        for(int i = 0; i < c1; ++i) {
            if(isPointInPolygon(s1[i], s2)) {
                printf("NO
    ");
                return;
            }
        }
        for(int i = 0; i < c2; ++i) {
            if(isPointInPolygon(s2[i], s1)) {
                printf("NO
    ");
                return;
            }
        }
        for (int i = 0; i < c1; i++) {
            for (int j = 0; j < c2; j++) {
                if (Intersection(s1[i], s1[(i + 1) % c1], s2[j], s2[(j + 1) % c2])) {
                    printf("NO
    ");
                    return;
                }
            }
        }
        printf("YES
    ");
    }
    
    int main() {
        int n, m;
        while (cin >> n >> m) {
            if(n == 0 && m == 0) break;
            Polygon s1, s2;
            for (int i = 0; i < n; ++i) {
                double x1, x2;
                scanf("%lf%lf", &x1, &x2);
                s1.push_back(Point(x1, x2));
            }
            for (int i = 0; i < m; ++i) {
                double x1, x2;
                scanf("%lf%lf", &x1, &x2);
                s2.push_back(Point(x1, x2));
            }
            if(s1.size()) s1 = Andrew(s1);
            if(s2.size()) s2 = Andrew(s2);
            solve(s1, s2);
        }
        return 0;
    }
    
  • 相关阅读:
    bzoj3757 苹果树
    bzoj2743 [HEOI2012]采花
    bzoj4241 历史研究
    bzoj4448 [Scoi2015]情报传递
    bzoj3295 [Cqoi2011]动态逆序对
    bzoj4034 [HAOI2015]T2
    bzoj3339 Rmq Problem
    BZOJ 1017 魔兽地图
    BZOJ 1021 循环的债务
    SUOI #37 清点更多船只
  • 原文地址:https://www.cnblogs.com/wulitaotao/p/11391819.html
Copyright © 2011-2022 走看看