【题解】The Great Divide [Uva10256]
【题解】The Great Divide [Uva10256]
传送门:\(\text{The Great Divide [Uva10256]}\)
【题目描述】
输入多组数据,每组数据给定 \(n\) 个红点坐标和 \(m\) 个蓝点坐标,判断是否可以用一条直线将两种颜色的点完全隔离开(直线不能经过某个点)。
【输入】
每组数据第一行为两个整数 \(n,m\),接下来 \(n+m\) 行每行两个整数 \(x,y\) 表示一个坐标,前 \(n\) 行为红点,后 \(m\) 行表示蓝点。
【输出】
如果存在这样一条直线输出 \(Yes\),否则输出 \(No\) 。
【样例】
样例输入:
4 3
100 600
200 400
600 500
300 700
400 100
600 200
500 300
4 3
100 600
400 100
600 200
500 300
200 400
600 500
300 700
0 0
样例输出:
Yes
No
【数据范围】
\(100\%:\) \(1\leqslant n,m \leqslant 500,\) \(-1000 \leqslant x,y \leqslant 1000\)
【分析】
凡是遇到计算几何的题目,先画张图出来:

观察发现:如果存在一条合法直线,两部分点的凸包必定相离。
两多边形相离的条件有:
\((1).\) 属于不同多边形的任意两边都不相交。
\((2).\) 一个多边形上的任意点都不被另一个多边形所包含。
求凸包可以 \(O(n)\) 解决,由于数据范围比较小,暴力枚举两个凸包进行判断就可以了。
判断线段相交为 \(O(1)\),\(PIP\) 可以用 \(O(n)\) 的射线法或者转角法,由于这里判断的是凸包,所以也可以用 \(O(logn)\) 的二分法,只是要注意凸包点集的顺序是顺时针还是逆时针,这里 \(WA\) 了无数遍。
时间复杂度为 \(O(n^3)/O(n^2logn)\) 。
【Code】
【射线法】
#include<algorithm>
#include<cstdio>
#include<cmath>
#define LD double
#define LL long long
#define Vector Point
#define Re register int
using namespace std;
const int N=1e5+3;
const LD eps=1e-8;
int n,T;
inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
struct Point{
LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
inline void in(){scanf("%lf%lf",&x,&y);}
};
inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
inline LD Len(Vector a){return sqrt(Dot(a,a));}
inline LD Angle(Vector a,Vector b){return acos(Dot(a,b)/Len(a)/Len(b));}
inline Point operator+(Point a,Vector b){return Point(a.x+b.x,a.y+b.y);}
inline Vector operator-(Point a,Point b){return Vector(a.x-b.x,a.y-b.y);}
inline Vector operator*(Vector a,LD x){return Vector(a.x*x,a.y*x);}
inline int pan_cross_LL(Point a,Point b,Point c,Point d){//判断两线段AB,CD是否相交
LD c1=Cro(b-a,c-a),c2=Cro(b-a,d-a);
LD d1=Cro(d-c,a-c),d2=Cro(d-c,b-c);
return dcmp(c1)*dcmp(c2)<=0&&dcmp(d1)*dcmp(d2)<=0;//这里重合也要算
}
inline bool cmp1(Point a,Point b){return a.x==b.x?a.y<b.y:a.x<b.x;};//按坐标排序
struct Poly{
int n,cnt;Point cp[N],Poi[N];
inline int ConvexHull(Point *P,Re n,Point *cp){
sort(P+1,P+n+1,cmp1);
Re t=0;
for(Re i=1;i<=n;++i){//下凸包
while(t>1&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
cp[++t]=P[i];
}
Re St=t;
for(Re i=n-1;i>=1;--i){//上凸包
while(t>St&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
cp[++t]=P[i];
}
return --t;//要减一
}
inline void sakura(){
for(Re i=1;i<=n;++i)Poi[i].in();
cnt=ConvexHull(Poi,n,cp);
}
}A,B;
inline int pan_PL(Point p,Point a,Point b){//判断点P是否在线段AB上
return !dcmp(Cro(p-a,b-a))&&min(a.x,b.x)<=p.x&&p.x<=max(a.x,b.x)&&min(a.y,b.y)<=p.y&&p.y<=max(a.y,b.y);
}
inline int PIP(Point *P,Re n,Point a){
Re cnt=0;LD tmp;
for(Re i=1;i<=n;++i){
Re j=i<n?i+1:1;
if(pan_PL(a,P[i],P[j]))return 2;//点在多边形上
if(a.y>=min(P[i].y,P[j].y)&&a.y<max(P[i].y,P[j].y))//纵坐标在该线段两端点之间
tmp=P[i].x+(a.y-P[i].y)/(P[j].y-P[i].y)*(P[j].x-P[i].x),cnt+=dcmp(tmp-a.x)>0;//交点在A右方
}
return cnt&1;//穿过奇数次则在多边形以内
}
inline int judge(){
for(Re i1=1;i1<=A.cnt;++i1){
Re j1=i1<A.cnt?i1+1:1;
for(Re i2=1;i2<=B.cnt;++i2){
Re j2=i2<B.cnt?i2+1:1;
if(pan_cross_LL(A.cp[i1],A.cp[j1],B.cp[i2],B.cp[j2]))return 0;//两线段相交
if(PIP(B.cp,B.cnt,A.cp[i1])||PIP(A.cp,A.cnt,B.cp[i2]))return 0;//点包含在内
}
}
return 1;
}
int main(){
// freopen("123.txt","r",stdin);
while(scanf("%d%d",&A.n,&B.n)&&A.n&&B.n)A.sakura(),B.sakura(),puts(judge()?"Yes":"No");
}
【二分法】
#include<algorithm>
#include<cstdio>
#include<cmath>
#define LD double
#define LL long long
#define Vector Point
#define Re register int
using namespace std;
const int N=1e5+3;
const LD eps=1e-8;
int n,T;
inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
struct Point{
LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
inline void in(){scanf("%lf%lf",&x,&y);}
};
inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
inline LD Len(Vector a){return sqrt(Dot(a,a));}
inline LD Angle(Vector a,Vector b){return acos(Dot(a,b)/Len(a)/Len(b));}
inline Point operator+(Point a,Vector b){return Point(a.x+b.x,a.y+b.y);}
inline Vector operator-(Point a,Point b){return Vector(a.x-b.x,a.y-b.y);}
inline Vector operator*(Vector a,LD x){return Vector(a.x*x,a.y*x);}
inline int pan_cross_LL(Point a,Point b,Point c,Point d){//判断两线段AB,CD是否相交
LD c1=Cro(b-a,c-a),c2=Cro(b-a,d-a);
LD d1=Cro(d-c,a-c),d2=Cro(d-c,b-c);
return dcmp(c1)*dcmp(c2)<=0&&dcmp(d1)*dcmp(d2)<=0;//这里重合也要算
}
inline bool cmp1(Point a,Point b){return a.x==b.x?a.y<b.y:a.x<b.x;};//按坐标排序
struct Poly{
int n,cnt;Point cp[N],Poi[N];
inline int ConvexHull(Point *P,Re n,Point *cp){
sort(P+1,P+n+1,cmp1);
Re t=0;
for(Re i=1;i<=n;++i){//下凸包
while(t>1&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
cp[++t]=P[i];
}
Re St=t;
for(Re i=n-1;i>=1;--i){//上凸包
while(t>St&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
cp[++t]=P[i];
}
return --t;//要减一
}
inline void sakura(){
for(Re i=1;i<=n;++i)Poi[i].in();
cnt=ConvexHull(Poi,n,cp);
for(Re i=1;i<=cnt/2;++i)swap(cp[i],cp[cnt-i+1]);//这里求出来的凸包点集按逆时针排列,转换一下
}
}A,B;
inline int pan_PL(Point p,Point a,Point b){//判断点P是否在线段AB上
return !dcmp(Cro(p-a,b-a))&&min(a.x,b.x)<=p.x&&p.x<=max(a.x,b.x)&&min(a.y,b.y)<=p.y&&p.y<=max(a.y,b.y);
}
inline int judge(Point a,Point L,Point R){//判断点AL是否在AR右边
return dcmp(Cro(L-a,R-a))>0;//必须严格以内
}
inline int PIP(Point *P,Re n,Point a){//判断点A是否在凸多边形Poly以内(二分法)
//点按顺时针给出
if(judge(P[1],P[2],a)||judge(P[1],a,P[n]))return 0;//在P[1_2]或P[1_n]外
if(pan_PL(a,P[1],P[2])||pan_PL(a,P[1],P[n]))return 1;//在P[1_2]或P[1_n]上
Re L=2,R=n-1;
while(L<R){//二分找到一个位置pos使得P[1]_A在P[1_pos],P[1_(pos+1)]之间
Re mid=L+R+1>>1;
if(judge(P[1],a,P[mid]))L=mid;
else R=mid-1;
}
if(judge(P[L],P[L+1],a))return 0;//在P[pos_(pos+1)]外
if(pan_PL(a,P[L],P[L+1]))return 1;//在P[pos_(pos+1)]上
return 1;
}
inline int judge(){
for(Re i1=1;i1<=A.cnt;++i1){
Re j1=i1<A.cnt?i1+1:1;
for(Re i2=1;i2<=B.cnt;++i2){
Re j2=i2<B.cnt?i2+1:1;
if(pan_cross_LL(A.cp[i1],A.cp[j1],B.cp[i2],B.cp[j2]))return 0;//两线段相交
if(PIP(B.cp,B.cnt,A.cp[i1])||PIP(A.cp,A.cnt,B.cp[i2]))return 0;//点包含在内
}
}
return 1;
}
int main(){
// freopen("123.txt","r",stdin);
while(scanf("%d%d",&A.n,&B.n)&&A.n&&B.n)A.sakura(),B.sakura(),puts(judge()?"Yes":"No");
}
【题解】The Great Divide [Uva10256]的更多相关文章
- UVA10256 The Great Divide
怎么又没人写题解,那我来贡献一发好了. 题目意思很简单,平面上有两种颜色的点,问你能否求出一条直线使两种颜色的点完全分开. 首先我们考虑两个点集相离的充要条件,这两个点集的凸包必须相离.(很好证明或者 ...
- 题解-CF1401E Divide Square
题面 CF1401E Divide Square 给一个正方形平面边长为 \(10^6\),给 \(n\) 条横线段和 \(m\) 条竖线段,每条线段都与正方形边缘相交且一条直线上不会有两条线段,求被 ...
- UVA10375 选择与除法 Choose and divide 题解
题目链接: https://www.luogu.org/problemnew/show/UVA10375 分析: 这道题可以用唯一分解定理来做. 什么是唯一分解定理?百度即可,这里也简介一下. 对于任 ...
- 【CF1445D】Divide and Sum 题解
题目链接 题意简介 将一个长度为 2n 的数列平均分为两个子数列 p 和 q 后,p 按从小到大排序,q 按从大到小排序. 排序后,记 p 为 \(\{x_i\}\) ,q 为 \(\{y_i\}\) ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- HDU 5783 Divide the Sequence(数列划分)
p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-s ...
- LeetCode OJ 题解
博客搬至blog.csgrandeur.com,cnblogs不再更新. 新的题解会更新在新博客:http://blog.csgrandeur.com/2014/01/15/LeetCode-OJ-S ...
- 2016 Multi-University Training Contest 5 Divide the Sequence
Divide the Sequence 题意: 给你一个序列A,问你最多能够分成多少个连续子序列,使得每个子序列的所有前缀和均不小于0 题解: 这题是比赛时候的水题,但我比的时候也就做出这一题, = ...
- HDU 5783 Divide the Sequence (贪心)
Divide the Sequence 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5783 Description Alice has a seq ...
随机推荐
- http代理阅读3 发送mem处理
每次客户端有可读数据触发时,优先检测是否还有数据没有发送,如果有则发送数据,然后在读取client数据 //向后端发送请求的调用过程 //ngx_http_upstream_send_request_ ...
- sql 训练及总结
1.sql语句中=与in的区别,=是指一对一之间的等于,而in是指一对多之间的:同样的道理,<>与 not in的区别,<>是指一对一之间的不等于,而not in是指一对多之 ...
- java中elasticsearch7.x关于nested类型的api使用,新增+更新
0,定义esHighClient 1 @Configuration 2 public class RestClientConfig { 3 4 //类似:200.188.22.20:9300,200. ...
- sync_with_stdio(false)和cin.tie(NULL)
std::ios::sync_with_stdio(false) 这个函数相当于是否兼容stdio的开关,默认为true C++为了兼容C,保证程序在使用了std::printf和std::cout的 ...
- [原题复现]2018HCTF WEB admin(session伪造、unicode漏洞、条件竞争)
简介 原题复现:https://github.com/woadsl1234/HCTF2018_admin 考察知识点:session伪造.unicode漏洞.条件竞争 线上平台:https:// ...
- cProfile分析程序性能
Python标准库中提供了三种用来分析程序性能的模块,分别是cProfile, profile和hotshot,另外还有一个辅助模块stats.这些模块提供了对Python程序的确定性分析功能,同时也 ...
- 使用Folx下载热门电影居然这么简单
在闲暇的时候,很多人会选择观看电影.电视剧来打发时间.对于一些热门的资源,可以通过网页搜索的方式,找到很多与之相对应的种子资源. 但有时候,一些不那么热门的资源就要花费较多时间搜索.有了Folx bt ...
- 如何用Camtasia将喜欢的视频做出复古的感觉
不知道各位可有看老电影的习惯,我个人觉得一些老电影那种别具一格的画面感是非常吸引人的韵味,尽管其色彩不是很鲜艳,但是这种黑白的感觉,对于现在的我们,往往有着不一样的吸引力.于是,我就尝试着用Camta ...
- FL Studio录制面板知识讲解
FL Studio录制面板可以设置与录制有关的选项,它还有一个用来设置音符对齐的全局吸附选择器.刚接触水果这款音乐制作软件的同学通常不是很清楚这里的知识的,下面小编就给大家讲解一下. 1.首先,我们来 ...
- vue 2.9.6升级到3X版本
先通过 npm uninstall vue-cli -g 卸载vue,然后再安装,但是vue -V时依然是2.9.6版本: 第一步: npm config get registry 第二步: npm ...