标签:
1.点与向量.
点与向量都用x,y两个坐标表示,所以我们在程序上暂时不做区分.
但是注意:
(1).点+向量=点;
(2).向量+向量=向量(向量-向量=向量+(相反向量));
(3).点-点=向量;
(4).点+点没有意义;
其中pt(point)表示点,vt(vector)表示向量.
1 struct pt{ 2 double x,y; 3 point(double x=0,double y=0):x(x),y(y){} 4 }; 5 typedef pt vt; 6 vt operator + (vt a,vt b){ return vt(a.x+b.x,a.y+b.y); } 7 vt operator - (pt a,pt b){ return vt(a.x-b.x,a.y-b.y); } 8 vt operator * (vt a,double x){ return vt(a.x*x,a.y*y); } 9 vt operator / (vt a,double x){ return vt(a.x/x,a.y/x); }
2.点的比较函数
在有些需要排序的时候会用到.
1 bool operator < (const pt &a,const pt &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); }
3.判断点相等的函数和避免误差的三态函数
浮点误差总是存在的,所以我们用三态函数dcmp来减少精度带来的问题.
1 const double eps=1e-8; 2 int dcmp(double x){ if(fabs(x)<eps) return 0; else return x<0?-1:1; } 3 bool operator == (const pt &a,const pt &b){ return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; }
4.向量的极角
向量的极角表示从x轴正半轴旋转到该向量所需要的角度.
使用C标准库里面的atan2函数即可,单位是弧度.
1 atan2(y,x);
1.向量的点积与叉积
$$cross(a,b)=a.x*b.y-a.y*b.x$$
这个是怎么来的呢?我们比较两个向量所在直线的斜率,如果b向量所在直线的斜率大(两个向量的斜率都存在的情况),那么就有$$\frac{b.y}{b.x}>\frac{a.y}{a.x}$$
然后去分母$$a.x*b.y>a.y*b.x$$
我们注意到,此时b向量所在的直线位于a向量所在直线的右手螺旋方向(a在b的左手螺旋方向).如果是小于号即b向量所在直线的斜率小,那么b向量所在的直线位于a向量所在直线的左手螺旋方向(a在b的右手螺旋方向).如果是等号即斜率一样,那么两条直线平行即向量a,b共线.
但这是两直线斜率都存在的情况.我们来讨论一下斜率不存在的情况:
(1).a所在直线的斜率不存在即\(a.x=0\).
若原不等式仍成立即\[0>a.y*b.x\],再讨论\(a.y\)的正负,可以证明b所在直线仍然位于a所在直线的右手螺旋方向.
(2).b所在直线的斜率不存在即\(b.x=0\).
若原不等式仍成立即$$a.x*b.y>0$$,再讨论\(b.y\)的正负,可以证明b所在直线仍然位于a所在直线的右手螺旋方向.
(3).a,b所在直线的斜率都不存在即\(a.x=b.x=0\).
此时不等式取等,平行.
综上,原不等式对应的结论永远成立.所以我们可以用叉积来判断两条直线的左右位置关系.
另外,叉积的几何意义是以这两个向量为邻边的平行四边形的有向面积(可用余弦定理证明),也就是两倍的三角形面积.
为什么说是有向面积呢?因为根据定义我们很容易发现\(cross(a,b)=-cross(b,a)\),所以算出来会带正负号!
1 double dot(vt a,vt b){ return a.x*b.x+a.y*b.y; } 2 double cross(vt a,vt b){ return a.x*b.y-a.y*b.x; } 3 double area2(pt a,pt b,pt c){ return cross(b-a,c-a); }
2.向量的模
1 double length(vt a){ return sqrt(dot(a,a)); }
3.两向量的夹角
通过点积来计算夹角的余弦值,再用一个反三角函数.
1 double angle(vt a,vt b){ return acos(dot(a,b)/length(a)/length(b)); }
4.向量的旋转.
将一个向量绕起点逆时针旋转\(\alpha\)弧度.
怎么操作呢?
我们先把这个向量的起点平移到坐标原点.写出向量终点的极坐标:$$x=rcos\theta$$
$$y=rsin\theta$$
旋转之后终点的极坐标为:
$$x‘=rcos(\theta+\alpha)$$
$$y‘=rsin(\theta+\alpha)$$
打开得到:
$$x‘=r(cos{\theta}cos{\alpha}-sin{\theta}sin{\alpha})=xcos{\alpha}-ysin{\alpha}$$
$$y‘=r(sin{\theta}cos{\alpha}+cos{\theta}sin{\alpha})=xsin{\alpha}+ycos{\alpha}$$
即:
$$x‘=xcos{\alpha}-ysin{\alpha}$$
$$y‘=xsin{\alpha}+ycos{\alpha}$$
1 vt rotate(vt a,double rad){ return vt(a.x*cos(rad)-a.y*sin(rad),a.x*sin(rad)+a.y*cos(rad)) }
5.复数
白书上提到了,但是我没有搞懂用来干嘛...貌似也比较慢,FFT里都是手写的,不管了.
1.线段相交
由于这是出现最频繁的问题,所以我们放在第一个说.
首先来定义一下规范相交:两线段相交且交点不是四个端点中的任何一个.
在解决判断线段是否相交的问题时,最容易想到的是解析几何的办法.但是和斜率相关的点斜式和斜截式都用不了,如果用一般式或两点式需要联立解方程,然后判断是否有解,如果有解还要判断是否在两条线段内部.这样很麻烦,而且误差不好控制.
对于不要求求出交点坐标的问题,我们采用一种神奇的方法.
首先一个引理:两线段\(AB\)与\(CD\)规范相交\(\Longleftrightarrow\)\(\overrightarrow{AC}\)与\(\overrightarrow{AD}\)分别在\(\overrightarrow{AB}\)左右两侧且\(\overrightarrow{CA}\)与\(\overrightarrow{CB}\)分别在\(\overrightarrow{CD}\)左右两侧
标签:
原文地址:http://www.cnblogs.com/Sunnie69/p/5577243.html