// 此博文为迁移而来,写于2015年4月9日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vxaq.html
1、前言
数学在讲解析几何,现在了解一下信息学中的计算几何也是极好的,和解析几何几乎是相通的。前面的内容比较简单,甚至自己看看就行都不值得写篇文章了,但是为了后面的内容作铺垫还是写写好了。
本章节从头到尾没有去看过别人的博文,基本上都是看的刘汝佳的《算法竞赛入门经典训练指南》,所以很多讲解是原创,有误敬请指出。几何问题背景知识多,内容杂乱,有些地方容易混淆,大家细看。
2、建模
开始做几何问题之前,必须先要将一些定义写好。我们都知道,向量是有方向,大小的量,而点是坐标系上的一个个点(词穷了= =。)但是,在信息学里面的平面坐标系中,向量和点的定义是一致的——只有x,y两个变量。因为一个点就相当于把向量的起点平移到坐标原点之后的终点坐标。下面就是他们的定义:
----------------------------------------------------------------------------------------------------
struct point
{
double x,y;
point(double x=0,double y=0):x(x),y(y) {} // 构造函数,方便代码编写
};
typedef point vector; //从程序实现上看,vector只是point的别名
----------------------------------------------------------------------------------------------------
3、符号
有了向量的表示,如何计算?这里要用到运算符重载,重载+、-、*、/、<、==。如何写数学里面都学了吧,我就不详说了。大家只要注意一下dcmp的作用。
----------------------------------------------------------------------------------------------------
vector operator + (vector a,vector b) { return vector(a.x+b.x,a.y+b.y); }
vector operator - (point a,point b) { return vector(a.x-b.x,a.y-b.y); }
vector operator * (vector a,double num) { return vector(a.x*num,a.y*num); }
vector operator / (vector a,double num) { return vector(a.x/num,a.y/num); }
bool operator < (point a,point b) { if (a.x!=b.x) return (a.x
const double eps=1e-10;
int dcmp(double x) { if (abs(x)<0)?-1:1; } // abs函数为绝对值
bool operator == (vector a,vector b) { return ( dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0); }
----------------------------------------------------------------------------------------------------
dcmp函数的作用是什么?当两个值差距很小时,同样会返回相同,即返回0,用以避免精度问题带来的麻烦。
4、基本运算
1、点积(Dot)。向量a和b的点积等于两者长度的乘积乘上它们夹角的余弦。夹角为从a到b逆时针旋转的角。因此,当夹角大于90°时,点积为负。顺便写上如何求向量长度(Length)和夹角(Angle):
----------------------------------------------------------------------------------------------------
double Dot(vector a,vector b) { return a.x*b.x+a.y*b.y; }
double Length(vector a) { return sqrt(Dot(a,a)); }
double Angle(vector a,vector b) { return acos(Dot(a,b)/Length(a)/Length(b)); } // acos为反余弦,全称arccos
----------------------------------------------------------------------------------------------------
2、叉积(Cross)。数学里暂时没学,但是作用非常大!后面的面积都需要用到它,我开始看的时候还半天没看懂。两个向量a和b的叉积等于a和b组成的三角形的有向面积的两倍。有向面积的概念是,朝着向量a看,如果向量b在你左边,则叉积大于0;如果在你右边,则小于0。

// 标准图已丢失
如上图所示,Cross(a,b)>0,且它的值为灰色阴影部分的面积。
----------------------------------------------------------------------------------------------------
double Cross(vector a,vector b) { return a.x*b.y-a.y*b.x; } // 叉积
double Area2(point a,point b,point c) { return Cross(b-a,c-a); } // 由a,b,c三个点构成的平行四边形面积
----------------------------------------------------------------------------------------------------
根据上述的点积,叉积的公式以及作用,我们可以比较方便的得到两个向量的位置关系:

括号里第一个数是点积,第二个数是叉积。设向量a水平向右,根据向量a,b的点积叉积的正负零情况,可以得到向量b的大致方向。这在以后将有很大的作用。
5、直线
在数学里面,我们已经学了直线的多种表达方式——两点式,一般式等等,信息学里面采用参数式方程。任何一条直线可以用该直线上一点P0和方向向量v表示,则直线上所有点P满足P=P0+tv,t是一个参数。则直线的参数式为: P=P0+tv
1、直线交点(lineIntersection)。设两条直线分别为P+t1v和Q+t2w,设向量u=P-Q,则可以得到:
----------------------------------------------------------------------------------------------------
point lineIntersection(point p,vector v,point q,vector w)
{
vector u=p-q;
double t=Cross(w,u)/Cross(v,w);
return p+v*t;
}
----------------------------------------------------------------------------------------------------
2、点到直线的距离(Point to line)。很简单,直接用叉积即平行四边形的面积除以底边就可得到。
----------------------------------------------------------------------------------------------------
double Distance_PTL(point x,point a,point b)
{
vector v1=a-x,v2=b-x;
return (abs(Cross(v1,v2)/Length(v1)));
}
----------------------------------------------------------------------------------------------------
3、点到线段的距离(Point to segement)。注意是线段!也就是说,如果点到线段所在直线的垂线并不在线段上,那么点到线段的距离并不是直接和到直线的距离一样(很拗口,慢慢看)。设投影点为Q,如果在线段AB上,即为P到直线AB的距离;如果在射线BA上,则所求距离为PA;否则为PB。如何判断Q的位置?如下图:
前面我们讲了利用点积叉积来判断两个向量的方向,这个地方就可以用到了。大家可以自己去试试v1,v2,v3之间的点积关系能够说明什么。
----------------------------------------------------------------------------------------------------
double Distance_PTS(point x,point a,point b)
{
if (a==b) return Length(x-a);
vector v1=b-a,v2=x-a,v3=x-b;
if (dcmp(Dot(v1,v2))<0) return Length(v2); // q在射线ba上
else if (dcmp(Dot(v1,v3))>0) return Length(v3); // q在射线ab上
else return fabs(Cross(v1,v2)/Length(v1)); // q在线段ab上
}
----------------------------------------------------------------------------------------------------
4、点在直线上的投影(lineProjection)。设AB的参数式为A+tv,P的投影点Q为Q=A+t0v,由于PQ⊥AB,则Dot(v,P-(A+t0v))=0,即Dot(v,P-A)-t0×Dot(v,v)=0,解出t0=Dot(v,x-a)/Dot(v,v),带入参数式,得Q点。
----------------------------------------------------------------------------------------------------
point lineProjection(point x,point a,point b)
{
vector v=b-a;
return (a+v*(Dot(v,x-a)/Dot(v,v)));
}
----------------------------------------------------------------------------------------------------
5、判断线段相交(Point to line)。判断条件:线段a的两个端点在线段b的两侧(即叉积符号不同)。
----------------------------------------------------------------------------------------------------
bool segmentIntersection(point a1,point a2,point b1,point b2)
{
double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
return (dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0);
}
----------------------------------------------------------------------------------------------------
6、多边形面积
将前面的知识全部铺垫好了,求多边形面积可以算是实战演练的第一步。求面积很简单,任取多边形的一个顶点(一般取读入的第一个顶点),从该点出发将多边形分成n-2个三角形,然后将面积加起来。
对于凸多边形来说,似乎比较好理解,如上图,S=S1+S2+S3+S4。凹多边形连接了每个顶点之后,可能会出现重叠面积和多边形以外的面积啊?可以确定的一点是,重叠面积=以外的面积(原因可以问你们数学老师)。所以无需顾虑,同样地,S=S1+S2+S3。
----------------------------------------------------------------------------------------------------
double polygonArea(point p[100],int n)
{
double area=0;
for (int i=1;i<=n-2;i++)
area+=Cross(p[i]-p[0],p[i+1]-p[0]);
return area/2;
}
----------------------------------------------------------------------------------------------------
7、总结
比较早就开始看这一章,但是搞了很久,主要是内容太杂了,搞得有点心烦。当然今天只讲了一些最基础的东西,后面将持续更新。
计算几何II——二维几何之凸包
计算几何III——二维几何之半平面交
计算几何IV——圆与圆的计算
计算几何V——三维几何(这玩意儿前提是我能搞懂= =)
- Java 面试知识点解析(一)——基础知识篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- 大数据基础知识问答----spark篇,大数据生态圈
Spark相关知识点 1.Spark基础知识 1.Spark是什么? UCBerkeley AMPlab所开源的类HadoopMapReduce的通用的并行计算框架 dfsSpark基于mapredu ...
- python 爬虫基础知识一
网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动的抓取万维网信息的程序或者脚本. 网络爬虫必备知识点 1. Python基础知识2. P ...
- hdu 2528:Area(计算几何,求线段与直线交点 + 求多边形面积)
Area Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- HDU 2036 改革春风吹满地【计算几何/叉乘求多边形面积】
改革春风吹满地 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- EOJ 1127. 多边形面积(计算几何)
题目链接:1127. 多边形面积(计算几何) 题意 按逆时针顺序给出 \(n\) 个点的坐标,求这些点围成的多边形的面积. 思路 选择多边形上的一个点,然后每次枚举之后的两个点,计算叉积,注意要保留符 ...
- 「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !
本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指南」一份涵盖大 ...
- 关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL))
关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL)) 欢迎fork本项目原始链接:关于图计算&图学习的基础知识概览:前置知识点学习 ...
- poj 1654 Area(计算几何--叉积求多边形面积)
一个简单的用叉积求任意多边形面积的题,并不难,但我却错了很多次,double的数据应该是要转化为long long,我转成了int...这里为了节省内存尽量不开数组,直接计算,我MLE了一发...,最 ...
随机推荐
- CSS3–1.css3 新增选择器
1.后代级别选择器 2.同辈级别选择器 3.伪类选择器 4.属性选择器 5.UI伪类选择器 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 T ...
- 【javascript】 for循环小技巧
最近在读[Jquery技术内幕],里面介绍了一种js for循环的实用写法. 一般写for循环是这么写的: var elemts = [1,2,3,4,5]; for(var i=0; i<el ...
- Delphi运算符总结
分类 运算符 操作 操作数 结果类型 范例 算术运算符(加法.减法和乘法运算符的结果为参加运算的两个数据中的精度高的类型) + 加 整数,实数 整数,实数 X + Y - 减 整数,实数 整数,实数 ...
- C# 一些常用的技巧代码
1.字符串风格成字符数组: 比如将字符串:23$123$45$转换成int[]这样的数组,你该怎么转换?其实你不用写那么的for循环,只需要一句话: int [] Relst =Array.Conve ...
- ASMCMD命令
安装好用的rlwrap工具,在环境变量里添加如下,就能实现显示当前路径(目录),目录补全的方便功能 alias asmcmd='rlwrap -r -i asmcmd –p' asmcmd>he ...
- 修改Apache配置文件开启gzip压缩传输
转自:http://down.chinaz.com/server/201202/1645_1.htm 最近无事研究一些Web的优化,用工具page speed检测网站时发现还没有开启gzip压缩,于是 ...
- PMP 第十二章 项目采购管理
1规划采购 2实施采购 3管理采购 4结束采购 1.合同的不同叫法?卖方的不同叫法? 2.规划采购管理的目的是什么?合同类型有哪些?不同的特点是什么?何种情况下应选择何种合同?自制或外购分析计算和合同 ...
- C# 使用 NPOI 库读写 Excel 文件
NPOI 是开源的 POI 项目的.NET版,可以用来读写Excel,Word,PPT文件.在处理Excel文件上,NPOI 可以同时兼容 xls 和 xlsx.官网提供了一份 Examples,给出 ...
- CE搜索内存数据的原理
最近发现有朋友在玩游戏时, 使用一款工具来修改游戏的部分数据,作弊的效果, 也就是CE(Cheat Engine),这款工具是 delphi 编写的, 于是好奇, 然后瞬间想到API OpenPr ...
- 【java基础】内存分析
在上次我们说的<重载与重写>呢,我们遗留了一个问题,就是运行结果的各异性,那今天,我们就来探究一下 内存里的天地. 首先呢,我们把mian ...