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

题目链接:UVA 10256

题意

有n个红点和m个蓝点,问是否存在一条直线能够分开红点和蓝点。

题解

分别求出红点和蓝点的凸包,判断两个凸包是否相交。

凸包不相交的条件:

  • 凸包上的任意点都在另一个凸包的外面
  • 凸包的任意线段都与另一个凸包不相交

代码

#include <bits/stdc++.h>
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\n");
            return;
        }
    }
    for(int i = 0; i < c2; ++i) {
        if(isPointInPolygon(s2[i], s1)) {
            printf("No\n");
            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\n");
                return;
            }
        }
    }
    printf("Yes\n");
}

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

参考

《算法竞赛入门经典》 刘汝佳 / 陈锋

原文地址:https://www.cnblogs.com/wulitaotao/p/11391803.html

时间: 2024-10-09 19:22:49

UVA 10256 The Great Divide (判断凸包相交)的相关文章

UVA 10256 The Great Divide (凸包,多边形的位置关系)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34148 [思路] 凸包 求出红蓝点的凸包,剩下的问题就是判断两个凸包是否相离. 需要确定两点: 1)  凸包上线段是否相交->相交 2)  凸包上的点是否包含在另一个凸包里->内含. [代码] 1 #include<cmath> 2 #include<vector> 3 #include<cstdio> 4 #include&

UVa 10256 The Great Divide,判断两个凸包是否相离

先从给出的两个点集中分别计算出两个凸包, 然后判断两个凸包是否相离. #include<cstdio> #include<vector> #include<cmath> #include<algorithm> using namespace std; const double eps = 1e-10; double dcmp(double x) { if(fabs(x) < eps) return 0; else return x < 0 ? -

UVA 10256 The Great Divide(凸包划分)

The Great Divide Input: standard input Output: standard output Time Limit: 8 seconds Memory Limit: 32 MB Somewhere in Gaul, there is a little village very like the village where Asterix and Obelix live. Not very long ago they had only one chief Altru

HDU6590 Code 判断凸包相交

网址:https://vjudge.net/problem/HDU-6590 题意: 找出一条直线使得黑点和白点全部分布在直线的同一侧. 题解: 支持向量机. 对每一类点求凸包,判断凸包是否相交即可. AC代码:挖坑待填. 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11260500.html

UVA10256 The Great Divide(凸包相交)

原题链接:UVA10256 The Great Divide 题意:平面上有n个红点和m个蓝点,是否存在一条直线使得任取一个红点和一个蓝点都在直线的异侧?这条直线不能穿过红点或蓝点 分析:显然,求红点凸包和蓝点凸包,如果这两个凸包有相交的部分就不存在这样的直线,否则就存在呗 #include <bits/stdc++.h> using namespace std; double eps=1e-15; double pi=acos(-1); struct Point{ double x,y; P

uva 10256 The Great Divide

题意:给定两个点集,一个红点集,另一个蓝点集,询问,能否找到一条直线能,使得任取一个红点和蓝点都在直线异侧. 思路:划分成两个凸包,一个红包,一个蓝包.两个凸包不相交不重合. 1.任取一个凸包中的点不在另一个凸包中. 2.任取一个凸包中的边与另一个凸包不相交. 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostrea

UVa 10256 (判断两个凸包相离) The Great Divide

题意: 给出n个红点,m个蓝点.问是否存在一条直线使得红点和蓝点分别分布在直线的两侧,这些点不能再直线上. 分析: 求出两种点的凸包,如果两个凸包相离的话,则存在这样一条直线. 判断凸包相离需要判断这两件事情: 任何一个凸包的任何一个顶点不能在另一个凸包的内部或者边界上. 两个凸包的任意两边不能相交. 二者缺一不可,第一条很好理解,但为什么还要判断第二条,因为存在这种情况: 虽然每个凸包的顶点都在另一个凸包的外部,但两个凸包明显是相交的. 1 //#define LOCAL 2 #include

EF框架操作postgresql,实现WKT类型坐标的插入,查询,以及判断是否相交

1.组件配置 首先,要下载.NET for Postgresql的驱动,npgsql,EF6,以及EntityFramework6.Npgsql,版本号 3.1.1.0. 由于是mvc项目,所以,把相应的配置文件写在web.config里面,如下: 1 <configSections> 2 <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?L

hdu 1086(判断线段相交)

传送门:You can Solve a Geometry Problem too 题意:给n条线段,判断相交的点数. 分析:判断线段相交模板题,快速排斥实验原理就是每条线段代表的向量和该线段的一个端点与 另一条线段的两个端点构成的两个向量求叉积,如果线段相交那么另一条线段两个端点必定在该线段的两边,则该线段代表的向量必定会顺时针转一遍逆时针转一遍,叉积必定会小于等于0,同样对另一条线段这样判断一次即可. #include <algorithm> #include <cstdio>