UVA10256 The Great Divide

怎么又没人写题解,那我来贡献一发好了。

题目意思很简单,平面上有两种颜色的点,问你能否求出一条直线使两种颜色的点完全分开。

首先我们考虑两个点集相离的充要条件,这两个点集的凸包必须相离。(很好证明或者画画图理解一下)

那么怎么判断两个凸包相离,考虑到这里的点的个数不多,我们可以用一种最暴力的方法。

枚举一个凸包上的所有点所有边,然后判断是否与另一个凸包相离即可。

点是否在多边形内?直接暴力转角法即可(不推荐射线法,好理解但不好写,精度不高)

边是否在多边形内,在两个凸包中分别枚举一条边,然后判断是否相交即可。

稍微注意一下精度问题即可,其实计算几何的题主要考验的就是代码的细节能力。

CODE

#include<cstdio>
#include<cmath>
#include<algorithm>
#define RI register int
using namespace std;
typedef double DB;
const int N=505;
const DB EPS=1e-10;
inline int dcmp(DB x)
{
    if (fabs(x)<EPS) return 0; return x<0?-1:1;
}
struct Point
{
    DB x,y;
    Point(DB X=0,DB Y=0) { x=X; y=Y; }
    inline friend bool operator <(Point A,Point B)
    {
        return dcmp(A.x-B.x)<0||(!dcmp(A.y-B.y)&&dcmp(A.y-B.y)<0);
    }
    inline friend bool operator ==(Point A,Point B)
    {
        return !dcmp(A.x-B.x)&&!dcmp(A.y-B.y);
    }
}a[N],b[N],cov_a[N],cov_b[N]; int n,m,cnt_a,cnt_b; DB x,y;
typedef Point Vector;
inline Vector operator -(Point A,Point B) { return Vector(A.x-B.x,A.y-B.y); }
class Computation_Geometry
{
    private:
        inline DB Dot(Vector A,Vector B)
        {
            return A.x*B.x+A.y*B.y;
        }
        inline DB Cross(Vector A,Vector B)
        {
            return A.x*B.y-A.y*B.x;
        }
        inline bool OnSegment(Point p,Point A,Point B)
        {
            return !dcmp(Cross(A-p,B-p))&&dcmp(Dot(A-p,B-p))<0;
        }
        inline bool IsPointInPolygon(Point p,Point *a,int n)
        {
            int t=0; for (RI i=1;i<=n;++i)
            {
                Point p1=a[i],p2=a[(i+1)%n+1];
                if (p1==p||p2==p||OnSegment(p,p1,p2)) return 1;
                int ret=dcmp(Cross(p2-p1,p-p1)),d1=dcmp(p1.y-p.y),d2=dcmp(p2.y-p.y);
                if (ret>0&&d1<=0&&d2>0) ++t; if (ret<0&&d2<=0&&d1>0) --t;
            }
            return t!=0;
        }
        inline bool SegmentProperIntersection(Point A,Point B,Point C,Point D)
        {
            DB c1=Cross(B-A,C-A),c2=Cross(B-A,D-A),c3=Cross(D-C,A-C),c4=Cross(D-C,B-C);
            return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
        }
    public:
        inline int ConvexHull(Point *a,int n,Point *p)
        {
            sort(a+1,a+n+1); n=unique(a+1,a+n+1)-a-1; RI i,top=0;
            for (i=1;i<=n;++i)
            {
                while (top>1&&dcmp(Cross(p[top]-p[top-1],a[i]-p[top]))<=0) --top;
                p[++top]=a[i];
            }
            int t=top; for (i=n-1;i;--i)
            {
                while (top>t&&dcmp(Cross(p[top]-p[top-1],a[i]-p[top]))<=0) --top;
                p[++top]=a[i];
            }
            if (n>1) --top; return top;
        }
        inline bool ConvexPolygonDisjoint(Point *a,int n,Point *b,int m)
        {
            RI i,j; for (i=1;i<=n;++i) if (IsPointInPolygon(a[i],b,m)) return 1;
            for (i=1;i<=m;++i) if (IsPointInPolygon(b[i],a,n)) return 1;
            for (i=1;i<=n;++i) for (j=1;j<=m;++j)
            if (SegmentProperIntersection(a[i],a[i%n+1],b[j],b[j%m+1])) return 1;
            return 0;
        }
}G;
int main()
{
    while (scanf("%d%d",&n,&m),n&&m)
    {
        RI i; for (i=1;i<=n;++i) scanf("%lf%lf",&x,&y),a[i]=Point(x,y);
        for (i=1;i<=m;++i) scanf("%lf%lf",&x,&y),b[i]=Point(x,y);
        cnt_a=G.ConvexHull(a,n,cov_a); cnt_b=G.ConvexHull(b,m,cov_b);
        puts(G.ConvexPolygonDisjoint(cov_a,cnt_a,cov_b,cnt_b)?"No":"Yes");
    };
    return 0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/10305920.html

时间: 2024-10-09 19:23:04

UVA10256 The Great Divide的相关文章

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

HDU 5783 Divide the Sequence(数列划分)

HDU 5783 Divide the Sequence(数列划分) Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)   Problem Description - 题目描述 Alice has a sequence A, She wants to split A into as much as possible continuous subsequences, satisfy

29. Divide Two Integers

Divide two integers without using multiplication, division and mod operator. If it is overflow, return MAX_INT. (1) log int divide(int dividend, int divisor) { if(dividend == 0) return 0; if(divisor == 0) return INT_MAX; double t1 = log(fabs(dividend

codeforces 792C. Divide by Three

题目链接:codeforces 792C. Divide by Three 今天队友翻了个大神的代码来问,我又想了遍这题,感觉很好,这代码除了有点长,思路还是清晰易懂,我就加点注释存一下...分类吧.删除一个数字模3为M的或删除两个模3为3-M的(还有一些要删零),具体看代码. #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<strin

Divide Groups 二分图的判定

Divide Groups Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1835    Accepted Submission(s): 657 Problem Description   This year is the 60th anniversary of NJUST, and to make the celebration mo

lintcode 中等题:Divide Two Integers 两个数的除法

题目 两个整数相除 将两个整数相除,要求不使用乘法.除法和 mod 运算符. 如果溢出,返回 2147483647 . 样例 给定被除数 = 100 ,除数 = 9,返回 11 解题  15%的通过率,减法,位运算?表示不知道如何下手. 法一:利用减法,超时,人工直接去除的一些情况太流氓. public class Solution { /** * @param dividend the dividend * @param divisor the divisor * @return the re

Divide Two Integers

不能使用乘法,除法和mod operator,实现除法功能. Divide two integers without using multiplication, division and mod operator. If it is overflow, return MAX_INT. 用减法可以实现,但是太慢了.算法里所做的优化都是为了节省时间. 不能忽视溢出的问题.例如,被除数是Integer.MIN_VALUE,除以-1,得到的结果对于Int型来说就溢出了,因此返回Integer.MAX_V

分治算法(Divide and Conquer)

分治算法 在计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并. 分治法所能解决的问题一般具有以下几个特征: 问题的规模缩小到一定的程度就可以容易地解决 问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质 利用该问题分解出的子问题的解可以合并为该问题的解 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问

[LeetCode] Divide Two Integers

In this problem, we are asked to divide two integers. However, we are not allowed to use division, multiplication and mod operations. So, what else can be use? Well, bit manipulations. Let's look at an example and see how bit manipulation might help.