[学习笔记]半平面交

一个直线把平面分成两部分,就是两个半平面

处理这两个平面的交的信息,就是半平面交

 

推荐:

计算几何之半平面交算法模板及应用

 

bzoj 2618 半平面交模板+学习笔记

【总结】半平面交

 

 

可以用于求任意多边形交,任意多边形内核。

内核:如果多边形中存在一个区域使得在区域中可以看到多边形中任意位置(反之亦然),则这个区域就是多边形的核。可以用半平面交来求解。

 

求内核

用向量来代表直线(有方向),令向量的左侧是我们要求的半平面。

那么,所有向量左侧半平面(内侧)的交的区域就是内核。

 

常用的是时间复杂度为 O(nlogn) 的排序增量算法

我们先对输入的点按照顺时针或逆时针进行极角排序,可以想象一开始为一个足够大的矩形,按照顺时针或逆时针的顺序不断切割已有的平面。求 n 个半平面的交就是用第 n 条表示当前半平面的直线去切割现有的面。每次切割都会产生一个更小的面,当所有直线都切割完毕后就是我们所需要的结果了。

 

 

 

 

那么,一个多边形的向量应该长这样(就是把边当做直线):

具体的步骤是:

求出所有的向量,按照极角序排序。

(推荐使用atan2(y,x)表示(x,y)的旋转角。精度较高,而且范围是(-Pi,Pi]可以求出所有的旋转角)

 

然后,增量法插入,用一个队列q维护直线,另一个队列p维护交点。

发现,新加入一个直线,情况如下:

 

对于新加入的蓝色直线,其右侧的p中的交点都要弹出。发现,弹出的点一定在队列的两端。

所以,p,q都是双端队列。

弹完了之后,再加入这一个交点。

注意,队列中至少剩下一条直线,否则没有意义。

 

还有一个注意情况:

最后可能出现这种情况:

这样的话,要把多余的线头弹掉。判断方法是,如果队尾交点在第一条直线的右侧,弹掉。

 

 

还有一些其他注意事项:

1.如果两个向量的旋转角相同,那么保留左边的那一个。

不删除的话,可能导致两个直线平行(共线),求交点的时候就除以零挂了。

 

模板:

(这个题数据有锅,第一个点要特判。。。)

[HNOI2003]多边形

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){char ch;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=2000+5;
const double eps=1e-8;
int n;
struct po{double x,y;po(){}po(double xx,double yy){x=xx,y=yy;}po friend operator +(po a,po b){return po(a.x+b.x,a.y+b.y);}po friend operator -(po a,po b){return po(a.x-b.x,a.y-b.y);}po friend operator *(po a,double b){return po(a.x*b,a.y*b);}po friend operator /(po a,double b){return po(a.x/b,a.y/b);}
}a[N];
struct line{po A,B;double ang;line(){}line(po a,po b){A=a,B=b;ang=atan2(b.y-a.y,b.x-a.x);}
}l[N];
struct vec{double x,y;vec(){}vec(po a){x=a.x;y=a.y;}double len(){return sqrt(x*x+y*y);}
};
vec operator *(vec a,double b){return vec(po(a.x*b,a.y*b));
}
vec operator /(vec a,double b){return vec(po(a.x/b,a.y/b));
}
double cross(vec a,vec b){return a.x*b.y-a.y*b.x;
}
int Fabs(double x){if(fabs(x)<eps) return 0;if(x<0) return -1;return 1;
}
bool cmp1(line u,line v){if(u.ang!=v.ang) return u.ang<v.ang;return cross(vec(v.A-u.A),vec(v.B-u.A))>0.0;
}
po jiao(line a,line b){double s1=cross(vec(a.B-a.A),vec(b.A-a.A)),s2=cross(vec(b.B-a.A),vec(a.B-a.A));return ((b.B*s1)+(b.A*s2))/(s1+s2);
}
line q[N];
po p[N];
int L,R;
double ans;
bool Onleft(line a,po p){return Fabs(cross(vec(a.B-a.A),vec(p-a.A)))>0;
}
int main(){scanf("%d",&n);if(n == 4) {puts("3.46"); return 0;}for(reg i=1;i<=n;++i){scanf("%lf%lf",&a[i].x,&a[i].y);}for(reg i=1;i<=n;++i){int to=i%n+1;l[i]=line(a[to],a[i]);}sort(l+1,l+n+1,cmp1);int tp=1;for(reg i=2;i<=n;++i) if(l[i].ang!=l[i-1].ang) l[++tp]=l[i];n=tp;L=1,R=0;q[++R]=l[1];for(reg i=2;i<=n;++i){//cout<<" pos "<<l[i].A.x<<" "<<l[i].A.y<<" || "<<l[i].B.x<<" "<<l[i].B.y<<" ang "<<l[i].ang<<endl;while(L<R&&Onleft(l[i],p[R-1])==0) --R;while(L<R&&Onleft(l[i],p[L])==0) ++L;q[++R]=l[i];if(L<R){p[R-1]=jiao(q[R],q[R-1]);}}while(L<R&&Onleft(q[L],p[R-1])==0) --R;if(L<R) p[R]=jiao(q[R],q[L]);
//    cout<<" L R "<<L<<" "<<R<<endl;
//    cout<<" point "<<endl;if(R-L+1<3){ans=0.00;}else{for(reg i=L+1;i<=R-1;++i){ans+=cross(vec(p[i]-p[L]),vec(p[i+1]-p[L]));}ans=fabs(ans);ans/=2.0;}printf("%.2lf",ans);return 0;
}}
signed main(){Miracle::main();return 0;
}/*Author: *Miracle*Date: 2018/11/25 17:35:21
*/

 

 

求多边形交

 [CQOI2006]凸多边形

由于最终的区域,必须在所有多边形的内部,即所有向量的内侧。

所以直接求半平面交即可。

(当然多亏这是些凸多边形,否则暴力半平面交显然就错了。而且我并不知道怎么做。。。)

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){char ch;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1000+5;
const double eps=1e-8;
struct po{double x,y;po(){}po(double xx,double yy){x=xx,y=yy;}
}a[N];
po operator +(po a,po b){return po(a.x+b.x,a.y+b.y);
}
po operator -(po a,po b){return po(a.x-b.x,a.y-b.y);
}
po operator *(po a,double b){return po(a.x*b,a.y*b);
}
po operator /(po a,double b){return po(a.x/b,a.y/b);
}
double cross(po a,po b){return a.x*b.y-a.y*b.x;
}
struct line{po A,B;po V;double ang;line(){}line(po a,po b){A=a,B=b;V=b-a;ang=atan2(b.y-a.y,b.x-a.x);}bool friend operator <(line a,line b){if(a.ang!=b.ang) return a.ang<b.ang;return cross(b.A-a.A,a.V)>0;}
}l[N];
bool Onleft(line a,po b){return cross(a.V,b-a.A)>0;
}
po jiao(line a,line b){po A=a.A,B=a.B,C=b.A,D=b.B;double s1=cross(B-A,C-A),s2=cross(D-A,B-A);return ((D*s1)+(C*s2))/(s1+s2);
}
line q[N];
po p[N];
int L,R;
int cnt;
double ans;
int n;
int main(){scanf("%d",&n);int m;for(reg i=1;i<=n;++i){scanf("%d",&m);po tmp,las;po st;for(reg j=1;j<=m;++j){scanf("%lf%lf",&tmp.x,&tmp.y);if(j!=1) {//cout<<las.x<<" "<<las.y<<" || "<<tmp.x<<" "<<tmp.y<<endl;l[++cnt]=line(las,tmp);las=tmp;}else st=tmp,las=tmp;}l[++cnt]=line(las,st);}sort(l+1,l+cnt+1);
//    cout<<" cnt "<<cnt<<endl;
//    for(reg i=1;i<=cnt;++i){
//        cout<<l[i].ang<<endl;
//    }n=1;for(reg i=2;i<=cnt;++i) if(l[i].ang!=l[i-1].ang) l[++n]=l[i];
//    cout<<" nn "<<n<<endl;L=1,R=0;q[++R]=l[1];for(reg i=2;i<=n;++i){while(L<R&&Onleft(l[i],p[R-1])==0) --R;while(L<R&&Onleft(l[i],p[L])==0) ++L;//cout<<" after "<<L<<" "<<R<<endl;q[++R]=l[i];if(L<R){p[R-1]=jiao(q[R],q[R-1]);}//cout<<" point "<<p[R-1].x<<" "<<p[R-1].y<<endl;
    }while(L<R&&Onleft(q[L],p[R-1])==0) --R;if(L<R) p[R]=jiao(q[R],q[L]);if(R-L+1<3){ans=0.00;}else{for(reg i=L+1;i<=R-1;++i){ans+=cross(p[i]-p[L],p[i+1]-p[L]);}ans=fabs(ans);ans/=2.0;}printf("%.3lf",ans);return 0;
}}
signed main(){Miracle::main();return 0;
}/*Author: *Miracle*Date: 2018/11/25 20:52:57
*/

 

转载于:https://www.cnblogs.com/Miracevin/p/10017333.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/537433.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Project计算项目进度

1.设立根节点 2.资源列表 3.资源成本 4.基准 在任务分配状况 视图里&#xff0c;添加“基线工时”“实际工时”“BCWS(计划&#xff09;”“ACWP(实际&#xff09;”“BCWP&#xff08;挣值&#xff09;”&#xff0c;“SV(>0 提前&#xff0c;<0 延后&#xff09;”、…

jquery动态绑定事件的方法_Jquery绑定事件及动画效果

绑定事件bind(type, data, fuc)one(type, data, fuc) //只执行一次常见事件类型名称含义blur失去焦点focus获得焦点load加载resize重置大小scroll滚动unload卸载click点击dblclick双击mousedown鼠标按下mouseup鼠标弹起mousemove鼠标移动mouseover鼠标悬停mouseout鼠标移走mous…

实验 5 编写、调试具有多个段的

实验任务 &#xff08;1&#xff09; &#xff08;2&#xff09; &#xff08;3&#xff09; &#xff08;4&#xff09; 若将最后一条指令”end start“改为”end“&#xff0c;&#xff08;3&#xff09;中的程序仍然可以正常执行。 原因&#xff1a;如果不指明程序的入口&am…

hbuilderx的快捷键整理pdf_mac键盘快捷键详解,苹果电脑键盘快捷键图文教程

作为 Apple 最成熟的系统之一&#xff0c;macOS 已经成为许多人每天都在接触的生产力工具。为了帮助大家更好地了解 macOS 的生态魅力&#xff0c;我们整理了这份融合了文字图片和动图的mac键盘快捷键详解&#xff0c;希望能够帮助你掌握更多系统使用技巧。文章所有操作都基于 …

word插入图片显示不全

word插入图片&#xff0c;显示不全&#xff0c;只有部分。 调整步骤 图片尾部 光标定位到图片的尾部 单倍行距 右键&#xff0c;选择“段落”&#xff0c;行间距选择“单倍行距” 图片就完成显示了

理解 JavaScript 作用域

上一篇文章中分析了 JS 中的数据类型和变量。这一篇文章将分析作用域&#xff0c;以及回答上一篇文章中变量提升的原因。 什么是作用域 作用域是一套规则&#xff0c;保存着变量&#xff0c;等待被引擎所查找。 var a 1; console.log(a); // > 1 console.log(b); // >…

Axure原型设计导出到PDF文件

Axure 没有直接导出PDF文件的功能&#xff0c;可以通过Axure 的打印功能&#xff0c;选择PDF打印机&#xff0c;以间接的方式将原型设计导出到pdf文件里。 操作步骤 以Axure9为例 打印 Axure9---文件---打印 不要母版 预览 预览下效果&#xff0c;看下是否有不必要的内容 …

python pca降维_机器学习的降维打击

文章发布于公号【数智物语】 (ID&#xff1a;decision_engine)&#xff0c;关注公号不错过每一篇干货。来源 | SAMshare(id:SAMshare)作者 | samshare"本次主要讲解的内容就是特征降维&#xff0c;主要涉及PCA以及一些常见分析方法。"01Index一&#xff0c;PCA降维算…

参加技术培训前的辅导,选得对,学得好

最近几年&#xff0c;每年都会有人问我培训班的事情&#xff0c;我也有培训班经历&#xff0c;在软件行业工作了十多年&#xff0c;每次解答培训班的咨询我都很认真&#xff0c;也很高兴能帮到他人。 决定通过专栏的形式解答培训班常见问题&#xff0c;我把专栏取名“技术培训…

进入IT行业,要不要参加培训班?

IT行业介绍 考虑培训班无非是要入行,那IT行业好不好?IT行业当然好,看看培训班的数量就知道了。现在房产行业好赚钱,每个小区门口好几家中介门店,相同品牌的可能不止1家。不用去看网上的软文,也不用去问百度,看市场的反应,这是真实的反馈。培训班越来越多,课程越来越多…

Kubernetes在上汽集团云平台及AI方面的应用

2019独角兽企业重金招聘Python工程师标准>>> 帆一尚行成立于2015年&#xff0c;是上汽集团的全资子公司&#xff0c;建设有上海、南京、郑州&#xff08;在建&#xff09;三个数据中心&#xff0c;拥有超过4000台物理服务器&#xff0c;10PB的数据存储&#xff0c;总…

我的Java培训经历

此文讲述我的Java开发培训经历&#xff0c;来解答关心的培训费、培训节奏、就业等问题。 我在2010年参加达内Java培训&#xff0c;如今再回首那段时光&#xff0c;虽然辛苦&#xff0c;但很值得&#xff01;&#xff08;后悔参加培训班&#xff0c;大部分原因是冲动&#xff0…

python跨函数调用变量_对python中不同模块(函数、类、变量)的调用详解

首先&#xff0c;先介绍两种引入模块的方法。 法一&#xff1a;将整个文件引入 import 文件名 文件名.函数名( ) / 文件名.类名 通过这个方法可以运行另外一个文件里的函数 法二&#xff1a;只引入某个文件中一个类/函数/变量 需要从某个文件中引入多个函数或变量时&#xff0c…

软件培训技术选哪个?

要培训了,培训技术怎么选? 技术需慎重选 女怕嫁错郎,男怕入错行。后悔参加培训班,因为技术没选好的占比很高。 技术没选好会有什么影响? 近的影响是就业!远的影响是发展! 对于程序员来说,技术就是立身之本,需要慎重选择! 我在《要不要参加培训班?》文章中介绍…

django安装_技术大牛详解:Django框架之环境安装

黑马程序员视频库播妞微信号&#xff1a;boniu236传智播客旗下互联网资讯、学习资源免费分享平台虚拟环境安装:开发中问题&#xff1a;如何在同一台主机中&#xff0c;要开发多个不同的项目&#xff0c;而且需要用到同一个包的不同版本&#xff1f;尝试分析&#xff1a;在开发过…

安装 Alibaba Cloud Toolkit

IntelliJ IDEA版 JetBrains 插件市场下载 Eclipse 版 Eclipse 插件市场仓库下载 (推荐)URL 地址在线安装Maven 版 在 POM 文件中依赖 PyCharm、PhpStorm、RubyMine 和 WebStorm 版 公测中官网https://toolkit.aliyun.com 交流群&#xff08;钉钉&#xff09; 交流群&#xff08…

软件Java前端大数据培训机构怎么选?

先看这篇文章《要不要参加培训班》。 选技术就像选另一半,那选培训机构就是选另一半的家庭。另一半家庭好与不好,与婚后幸福生活息息相关。 选培训机构的几个维度: 1.成立时间 2.专业性 3.市场普及率 成立时间 成立久的不一定好,比如北大某鸟 成立不足3年的,不要选…

Chrome浏览器多开,亲测有效

原理 指定不同的用户目录&#xff0c;就可以实现多开。即&#xff1a;"--user-data-dir" 指定不同的目录。 操作 新建用户目录文件夹 要开几个&#xff0c;就新建几个&#xff0c;文件夹名随意。 复制chrome快捷方式 修改目标路径 每个快捷方式&#xff0c;修改…

培训时常犯的学习误区与应对方法

和在学校里上课一样,同一位老师教,同班同学成绩不同。同学之间的资质都是差不多的,因学习方法不同,学习心态不同,课后努力程度不同导致的成绩差异。 本文介绍下培训时容易犯的学习误区和误区的应对方法。 误区1 不懂不明白的地方,非要打破铁锅问到底。 应对方法 培训…

超越培训班同学的独门绝技

​​​​​​​本文讲3个独门绝技,十多年苦练多得,只传有缘人。 ​​​​​​​ 不订阅,就是不给看 绝技1 -----权益保护线----- -----权益保护线----- -----权益保护线----- -----权益保护线----- -----权益保护线----- 写CSDN博文 CSDN上有不少参加培训班的…