【UVA10256】The Great Divide(凸包相离判定)

提交地址:

题目:


pdf:https://uva.onlinejudge.org/external/102/10256.pdf

n个红点,m个蓝点,是否存在一条直线,使得任取一个红点和一个蓝点都在直线的异侧?这条直线不能穿过红点或者蓝点

解题思路:


先求出红点和蓝点的凸包,如果这两个凸包是相离的,那么一定能找到一个满足条件的直线,问题转化为判断两个凸包是否相离。

(1)任取一个红点(或者蓝点),如果这个红点(或者蓝点)都不在那一个凸包内(点在多边形内判定), 那么这两个凸包有可能相离。

(2)光满足条件(1)还不够,因为可能会出现下图这样的情况,所以还需要判断两个凸包的任意两条边之间是否相交。

(3)当凸包是一个点或者线段需要特判。

ac代码:


#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const double eps = 1e-6;
const int maxn = 550;
int dcmp(double x)//精度三态函数(>0,<0,=0)
{
    if (fabs(x) < eps)return 0; //等于
    else return x < 0 ? -1 : 1;//小于,大于
}
struct Point{
    double x, y;
    Point(double x = 0, double y = 0):x(x),y(y){}
    friend bool operator == (Point a, Point b)
    {
        return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
    }
    friend bool operator < (Point a, Point b)
    {
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
};
typedef Point Vector;

Vector operator - (Vector a, Vector b)//向量减法
{
    return Vector(a.x - b.x, a.y - b.y);
}

double Dot(Vector a, Vector b)//点积
{
    return a.x * b.x + a.y * b.y;
}
double Cross(Vector a, Vector b)//外积
{
    return a.x * b.y - a.y * b.x;
}


bool Onsegment(Point p, Point a1, Point a2)
{
    return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
}
bool JudgeSegmentIntersect(Point A, Point B, Point C, Point D) //线段相交(包括端点)
{
    return
            dcmp(max(A.x, B.x) - min(C.x, D.x)) >= 0
            && dcmp(max(C.x, D.x) - min(A.x, B.x)) >= 0
            && dcmp(max(A.y, B.y) - min(C.y, D.y)) >= 0
            && dcmp(max(C.y, D.y) - min(A.y, B.y)) >= 0
            && dcmp(Cross(C - A, D - A)*Cross(C - B, D - B)) <= 0
            && dcmp(Cross(A - C, B - C)*Cross(A - D, B - D)) <= 0;
}

int isPointInPolygon(Point p, Point v[], int n)//n多边形顶点个数
{
    int wn = 0;
    for(int i = 0; i < n; i++)//多边形的端点从0开始存
    {
        if(Onsegment(p, v[i], v[(i+1)%n])) return -1;//在边界上
        int k = dcmp(Cross(v[(i+1)%n] - v[i], p-v[i]));
        int d1 = dcmp(v[i].y - p.y);
        int d2 = dcmp(v[(i+1)%n].y - p.y);
        //后两个条件确保射线能穿过多边形的这条边
        if(k>0 && d1<=0 && d2>0) wn++;//p在v[i]和v[(i+1)%n]向量左侧且y值在[v[i].y,v[(i+1)%n.y)
        if(k<0 && d2<=0 && d1>0) wn--;//右侧,且[v(i+1)%n.y, v[i].y)
    }
    if(wn!=0) return 1;//内部
    return 0;//外部
}

int ConvexHull(Point *p, int n, Point* ch)//凸包,ch存结果
{
    sort(p, p+n);//先x后y
    int m = 0;//ch存最终的凸包顶点,下标从0开始
    for(int i = 0; i < n; i++)
    {
        //m是待确定的
        while(m > 1 && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) m--;
        ch[m++] = p[i];
    }
    int k = m;
    for(int i = n-2; i >= 0; i--)
    {
        while(m > k && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) m--;//同样的方向
        ch[m++] = p[i];
    }
    if(n>1) m--;//m是凸包上的点数+1,相当于n,ch[m]和ch[0]相同,遍历的时候<m即可
    return m;
}

Point p1[maxn], p2[maxn], ch1[maxn], ch2[maxn];
int n, m, m1, m2;
bool check()
{
    if(m1 == 1 && m2 == 1) return ch1[0] == ch2[0] ? false : true;
    else if(m1 == 1 && m2 == 2) return !Onsegment(ch1[0], ch2[0], ch2[1]);
    else if(m1 == 2 && m2 == 1) return !Onsegment(ch2[0], ch1[0], ch1[1]);
    else if(m1 == 2 && m2 == 2) return !JudgeSegmentIntersect(ch1[0], ch1[1], ch2[0], ch2[1]);
    else if(m1 == 1 && m2 > 2) return !isPointInPolygon(ch1[0], ch2, m2);
    else if(m2 == 1 && m1 > 2) return !isPointInPolygon(ch2[0], ch1, m1);
    else if(m1 == 2 && m2 > 2)
    {
        for(int i = 0; i < m2; i++)
            if(JudgeSegmentIntersect(ch1[0], ch1[1], ch2[i], ch2[(i+1)%m2])) return false;//线段是否在另一个凸包的边上
        int d1 = isPointInPolygon(ch1[0], ch2, m2);
        if(d1 == -1 || d1 == 1) return false;
        int d2 = isPointInPolygon(ch1[1], ch2, m2);
        if(d2 == -1 || d2 == 1) return false;
        return true;
    }
    else if(m2 == 2 && m1 > 2)
    {
        for(int i = 0; i < m1; i++)
            if(JudgeSegmentIntersect(ch2[0], ch2[1], ch1[i], ch1[(i+1)%m1])) return false;
        int d1 = isPointInPolygon(ch2[0], ch1, m1);
        if(d1 == -1 || d1 == 1) return false;
        int d2 = isPointInPolygon(ch2[1], ch1, m1);
        if(d2 == -1 || d2 == 1) return false;
        return true;
    }
    else//m1>2 m2>2
    {
        for(int i = 0; i < m1; i++)
            for(int j = 0; j < m2; j++)
                if(JudgeSegmentIntersect(ch1[i], ch1[(i+1)%m1], ch2[j], ch2[(j+1)%m2])) return false;
        for(int i = 0; i < m1; i++)
        {
            int d = isPointInPolygon(ch1[i], ch2, m2);
            if(d == -1 || d == 1) return false;
        }
        for(int i = 0; i < m2; i++)
        {
            int d = isPointInPolygon(ch2[i], ch1, m1);
            if(d == -1 || d == 1) return false;
        }
        return true;
    }

}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    while(scanf("%d %d",&n, &m))
    {
        if(n == 0 && m == 0) break;
        for(int i = 0; i < n; i++) scanf("%lf %lf", &p1[i].x, &p1[i].y);
        for(int i = 0; i < m; i++) scanf("%lf %lf", &p2[i].x, &p2[i].y);
        m1 = ConvexHull(p1, n, ch1);
        m2 = ConvexHull(p2, m, ch2);
        if(check()) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
发布了299 篇原创文章 · 获赞 81 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Cassie_zkq/article/details/100942348