首先,欢迎大家来访问我老师的OJ:小白菜OJ

你是新入门OI的小白吗?
你正在苦于网上的资料不足吗?
你正在因各种blog写得不清不楚、艰涩难懂、千篇一律、满篇术语像LB一样而烦恼吗?
欢迎来到小白菜OJ!
这里有最易懂的视频讲解、基于HustOJ和阿里云的稳定、先进OJ
并且——完全免费!
小白菜OJ——信息学竞赛在线自学系统(caioj.cn)


以上为广告内容

说实话我觉得这道题才是真正的计算几何题
相对于这道题正方形那道真是太水了

正文


题面传送门(需要注册账号)

大意:
你按顺序丢了一堆线段到平面上,问你能直接拿起几根(不用搬走其他的线段)

前置知识

不是前置知识的东西:
本文使用结构体储存点和线段
所有的坐标都在笛卡儿坐标系中定义
说人话就是我用的是平面直角坐标系

端点结构体:

struct point
{double x,y;//横、纵坐标
};

线段结构体:

struct segment
{point l,r;//懒得打编号了,就直接记作左右端点(虽然可能不科学)
}

叉积

向量积,数学中又称外积、叉积,物理中称矢积、叉乘,是一种在向量空间中向量的二元运算。
                                           ——百度百科

向量的坑以后再补
叉积是什么?
我也想知道
叉积就是两个向量形成的平行四边形的面积大小。
CA→\overrightarrow{CA}CA与CB→\overrightarrow{CB}CB的叉积记为CA→×CB→\overrightarrow{CA}\times\overrightarrow{CB}CA×CB
就像这样:

图中平行四边形的面积就是CA→×CB→\overrightarrow{CA}\times\overrightarrow{CB}CA×CB(的大小)
(其实叉积是也一个向量,但我们在这里只讨论它的大小了啦!)

计算方法:
我们可以由三个点的坐标(图中的A,B,CA,B,CA,B,C)计算出两个向量的叉积
推导:
平行四边形的面积可以由2S△ABC2S_{\triangle ABC}2S△ABC​得到
作辅助矩形CDFECDFECDFE:

易得:
S△ABC=S矩形CDFE−S△ACE−S△BCD−S△ABFS_{\triangle ABC}=S_{矩形CDFE}-S_{\triangle ACE}-S_{\triangle BCD}-S_{\triangle ABF}S△ABC​=S矩形CDFE​−S△ACE​−S△BCD​−S△ABF​
=xB∗yA−12∗xA∗yA−12∗xB∗yB−12∗(xB−xA)∗(yA−yB)=x_B*y_A-\frac12*x_A*y_A-\frac12*x_B*y_B-\frac12*(x_B-x_A)*(y_A-y_B)=xB​∗yA​−21​∗xA​∗yA​−21​∗xB​∗yB​−21​∗(xB​−xA​)∗(yA​−yB​)
=xB∗yA−12∗xA∗yA−12∗xB∗yB−12∗xB∗yA+12∗xB∗yB+12∗xA∗yA−12∗xA∗yB=x_B*y_A-\frac12*x_A*y_A-\frac12*x_B*y_B-\frac12*x_B*y_A+\frac12*x_B*y_B+\frac12*x_A*y_A-\frac12*x_A*y_B=xB​∗yA​−21​∗xA​∗yA​−21​∗xB​∗yB​−21​∗xB​∗yA​+21​∗xB​∗yB​+21​∗xA​∗yA​−21​∗xA​∗yB​
=12∗xB∗yA−12∗xA∗yB=\frac12*x_B*y_A-\frac12*x_A*y_B=21​∗xB​∗yA​−21​∗xA​∗yB​
暴力果然是有用的
所以CA→×CB→\overrightarrow {CA}\times\overrightarrow {CB}CA×CB就可以表示为:
(xB−xC)(yA−yC)−(xA−xC)(yB−yC)(x_B-x_C)(y_A-y_C)-(x_A-x_C)(y_B-y_C)(xB​−xC​)(yA​−yC​)−(xA​−xC​)(yB​−yC​)

说了这么多,叉积有什么用呢?
好吧我们在这里只是用了一个性质:
如果记CCC为原点的话
那么如果是这样的一个情况:

我们会发现,CA→×CB→\overrightarrow{CA}\times\overrightarrow{CB}CA×CB是小于零的!
经过人类几千年以来的观察, 叉积总是在CA→\overrightarrow{CA}CA位于CB→\overrightarrow{CB}CB的顺时针方向时小于零,在CA→\overrightarrow{CA}CA位于CB→\overrightarrow{CB}CB所在直线上时等于零,在CA→\overrightarrow{CA}CA位于CB→\overrightarrow{CB}CB的顺时针方向时
因此,叉积的正负性可以用于判断从A⃗\vec AA到B⃗\vec BB的旋转方向。

真正的正文:

我们来看看两条相交的线段

有没有发现相对于AAA,与它处于同一条线段的另一点CCC与其它两点B,DB,DB,D的关系?
好像AC→\overrightarrow{AC}AC总是被夹在AB→\overrightarrow{AB}AB和AD→\overrightarrow{AD}AD中间呢!
仔细看一下好像对于每一个点都是酱紫的诶!
那我们就可以以AAA做基准点,判断B,DB,DB,D是不是在CCC的两边(也就是AB→×AC→\overrightarrow{AB}\times\overrightarrow{AC}AB×AC与AD→×AC→\overrightarrow{AD}\times\overrightarrow{AC}AD×AC不同号)就好啦!
等等!
还没好呢!
要是这样呢?


emm……那就再用B做基准点判一次咯……
所以代码就出来了:

bool intersect(line a,line b)
{#define A a.l#define B b.l#define C a.r#define D b.r//这几行的意思就是用ABCD四个点表示两条线段的四个端点if(cp(C,B,A)*cp(C,D,A)<0&&cp(D,A,B)*cp(D,C,B)<0)return 1;return 0;#undef A#undef B#undef C#undef D//这是取消上面的快捷表示,防止以后要用到ABCD
}

且慢!
如果这样呢?

这样的话BC→×BD→\overrightarrow{BC}\times\overrightarrow{BD}BC×BD就是0了啊!
那要不直接把&lt;&lt;<改成≤\le≤?
嘿嘿嘿~~~
直接上图:

这种情况下会错判
所以!
我们只能暴力判断了!
我们就加入一个东西:
这个东西叫做快速排斥判断。
它的工作原理如下:

我们用两个矩形框住两条线段
然后判断两个矩形是否有重叠部分
没有的话两条线段就肯定不会相交啊!
这时候我们就把它排除掉。
这个代码也不难:

int amaxx=max(a.l.x,a.r.x),amaxy=max(a.l.y,a.r.y),bmaxx=max(b.l.x,b.r.x),bmaxy=max(b.l.y,b.r.y);
int aminx=min(a.l.x,a.r.x),aminy=min(a.l.y,a.r.y),bminx=min(b.l.x,b.r.x),bminy=min(b.l.y,b.r.y);
if(amaxx<bminx||bmaxx<aminx||amaxy<bminy||bmaxy<aminy)return 0;

最终代码:

#include<cstdio>
#include<cstring>
using namespace std;
double max(double a,double b)
{return a>b?a:b;}
double min(double a,double b)
{return a<b?a:b;}
struct point
{double x,y;point operator -(point b){return (point){x-b.x,y-b.y};}
};
struct line
{point l,r;
}a[11000];
double cp/*Cross product*/(point a,point b,point o)//OA*OB
{point A=a-o,B=b-o;return A.x*B.y-A.y*B.x;
}
bool intersect(line a,line b)
{int amaxx=max(a.l.x,a.r.x),amaxy=max(a.l.y,a.r.y),bmaxx=max(b.l.x,b.r.x),bmaxy=max(b.l.y,b.r.y);int aminx=min(a.l.x,a.r.x),aminy=min(a.l.y,a.r.y),bminx=min(b.l.x,b.r.x),bminy=min(b.l.y,b.r.y);if(amaxx<bminx||bmaxx<aminx||amaxy<bminy||bmaxy<aminy)return 0;#define A a.l#define B b.l#define C a.r#define D b.rif(cp(C,B,A)*cp(C,D,A)<=0&&cp(D,A,B)*cp(D,C,B)<=0)return 1;#undef A#undef B#undef C#undef Dreturn 0;
}
bool v[11000];
int main()
{int n;scanf("%d",&n);#define L a[i].l#define R a[i].rfor(int i=1;i<=n;i++)scanf("%lf%lf%lf%lf",&L.x,&L.y,&R.x,&R.y);#undef L#undef Rmemset(v,1,sizeof(v));for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++)if(intersect(a[i],a[j])){v[i]=0;break;}for(int i=1;i<=n;i++)v[i]&&printf("%d ",i);//&&是短路运算符,就是只有前面一个是真才会执行后面的语句,这样会比if快一点(?)return 0;
}

历时两天,终于写完~~

caioj1212:【计算几何】判断线段相交(快速排斥判断与跨立实验)相关推荐

  1. 快速排斥实验amp;跨立实验 判断两直线是否相交

    两条线段有且仅有一个公共点,且这个点不是任何一条线段的端点时,称这两条线段是严格相交的. 也就是说线段不严格相交时可以将端点作为交点,但本文不讨论不严格相交,只讨论严格相交的情况(即使它们在算法实现上 ...

  2. 计算几何--快速排斥实验和跨立实验

    1.快速排序实验 两条线段有且仅有一个公共点,且这个点不是任何一条线段的端点时,称这两条线段是严格相交的.快速排斥实验能很快的排除掉线段不相交的情况,但并没法成为线段相交的充要条件,在快速排斥实验之后 ...

  3. 【计算几何】快速排斥实验和跨立实验

    1.快速排序实验 两条线段有且仅有一个公共点,且这个点不是任何一条线段的端点时,称这两条线段是严格相交的.快速排斥实验能很快的排除掉线段不相交的情况,但并没法成为线段相交的充要条件,在快速排斥实验之后 ...

  4. 计算几何——快速排斥实验和跨立实验

    两条线段有且仅有一个公共点,且这个点不是任何一条线段的端点时,称这两条线段是严格相交的. 也就是说线段不严格相交时可以将端点作为交点,但本文不讨论不严格相交,只讨论严格相交的情况(即使它们在算法实现上 ...

  5. 快速排斥实验和跨立实验

    矢量 如果一条线段的端点是有次序之分的话,那么这种线段就称为 有向线段,如果有向线段p1p2的起点p1在坐标的原点,则可以把它称为矢量p2 矢量的加减 设二维矢量 P = (x1, y1), Q = ...

  6. 计算几何 快速排斥和跨立实验 判断两线段相交

    线段P1P2, Q1Q2,判断其是否相交,通过快速排斥和跨立实验则说明相交 首先要知道:向量a×向量b(×为向量叉乘),若结果小于0,表示向量b在向量a的逆时针方向:若结果大于0,表示向量b在向量a的 ...

  7. 判断两线段是否相交——快速排斥与跨立实验

    如何判断两条线段是否相交呢?如果是我们去解决这个问题,用眼睛很容易就看出来了,但是如果用计算机来解决这个问题,该怎么办呢?下面介绍两个方法,这两个方法结合起来就能完美解决这个问题了. 一.快速排斥 对 ...

  8. 快速排斥、跨立实验判断线段是否相交

    写在前面 在其他博客中看到这方面的知识,很多都是重复,并且说的总是云里雾里的,所以这里我就自己总结一下这种问题如何求解,判断两个线段是否相交在前面我们提到了会用到叉积的一点知识,那么这里就来详细说一下 ...

  9. 【代码超详解】ZOJ 2551 / POJ 2653 Pick-up Sticks(快速排斥实验 + 跨立实验判断线段是否相交 · 模板)

    一.传送门 http://poj.org/problem?id=2653 https://zoj.pintia.cn/problem-sets/91827364500/problems/9182736 ...

最新文章

  1. SPRING3.X JSON 406 和 中文乱码问题
  2. python基础语法3_python基础语法三
  3. java类内存中只能运行一个实例对象
  4. PHP上传文件到七牛云和阿里云
  5. 研讨会 | 知识工程与问答技术研讨会 (KEQA2018)
  6. python自动化测试开发_基于python的selenium2自动化测试从基础到实战(Python3、selenium2、自动化测试、web测试)...
  7. 比特币中的密码学知识汇总
  8. 使用sysbench来测试Row Cache解惑
  9. c2061 dword 语法错误_解决'PMIB_ICMP_EX':undeclared identifier
  10. 什么是波导的简并波,矩形波导和圆波导中的简并有何异同
  11. X264编码h264
  12. 手机点餐系统概述_餐厅点餐系统需求分析
  13. android仿微信播放视频播放器,vue DPlayer 仿微信朋友圈视频播放效果
  14. openrasp-iast 灰盒扫描工具
  15. android开发中TabHost使用方法
  16. vscode 程序员鼓励师_把软萌程序猿鼓励师装进VScode里?最强交互彩虹屁,GitHub2.5k星,爱上写代码...
  17. 软文推广标题的写法,怎么才能让软文标题更有吸引力
  18. php 英文转中文,php如何将英文引号转换为中文引号
  19. 推动中国制造升级,汽车装配车间生产流水线 3D 可视化
  20. 〔王鹰教程五〕和弦的分类记忆法

热门文章

  1. 使用开源库 SDWebImage 异步下载缓存图片(持续更新)
  2. Centos磁盘占满
  3. python function at 0x00000_Python函数装饰器原理与用法详解
  4. SELECT SINGLE 和 SELECT ENDSELECT的区别!
  5. MATLAB作图基础准备及入门
  6. 目标检测算法——车辆牌照识别数据集汇总 2(附下载链接)
  7. 工业机器人综合实训平台
  8. 点晴OA和钉钉有何不同?
  9. SSM毕设项目校园快递配送系统jy0o2(java+VUE+Mybatis+Maven+Mysql)
  10. 上传无限制服务器,安全专家验证 PayPal 服务器存在无限制文件上传漏洞过程