double的比较大小(主要是判等)
const double eps=1e-9;
int dcmp(double x,double y){
if(fabs(x-y)<eps)
return 0;
if(x>y)
return 1;
return -1;
}
//判断正负
int sgn(double d){
if(fabs(d) < eps)
return 0;
if(d > 0)
return 1;
return -1;
}
常用头文件&小数定义&取整方法
#include <cstdio>
#include <cmath>
const double eps=1e-9;
const double pi=acos(-1.0);
const double inf=1e100;
int fx=floor(x); //向下取整
int cx=ceil(x); //向上取整
int rx=round(x); //四舍五入取整
点的定义
struct Point{
double x;
double y;
Point(double x = 0, double y = 0):x(x),y(y){} //此处定义可以直接Point a=Point(x,y)定义
};
向量的定义
既有大小又有方向的量叫做向量
在计算机中我们常用坐标表示
这样看来,向量这个结构体貌似与点没有任何区别,因此可以
#define Vector Point
struct Point{
double x;
double y;
Point(double x = 0, double y = 0):x(x),y(y){}
};
内积运算(又称数量积点积)
α⋅β=|α||β|cosθ``
几何意义
向量α
在向量β的投影α′(带有方向性)与β的长度乘积
若α与β的夹角为锐角,则其内积为正
若α与β的夹角为钝角,则其内积为负
若α与β的夹角为直角,则其内积为0
计算方法
α=(x1,y1) β=(x2,y2)
α⋅β=x1* x2+y1* y2
double Dot(Vector a,Vector b){
return a.x*b.x+a.y*b.y;
}
外积运算(又称向量积,叉积)
α×β=|α||β|sinθ
θ表示向量α旋转到向量β所经过的夹角
几何意义
向量α与β所张成的平行四边形的有向面积
判断外积的符号
右手定则
α×β
若β在α的逆时针方向,则为正值
顺时针则为负值
两向量共线则为0
double Cross(Vector A, Vector B){
return A.x*B.y-A.y*B.x;
}
重载向量运算符
//点与点之间的加法运算没有意义
//点与向量相加得到另一个点
//向量与向量相加得到另外一个向量
Vector operator + (Vector A, Vector B){
return Vector(A.x+B.x, A.y+B.y);
}
//两个点之间作差将得到一个向量,A−B将得到由B指向A的向量BA
Vector operator - (Point A, Point B){
return Vector(A.x-B.x, A.y-B.y);
}
//向量与实数相乘得到等比例缩放的向量
Vector operator * (Vector A, double p){
return Vector(A.x*p, A.y*p);
}
//向量与实数相除得到等比例缩放的向量
Vector operator / (Vector A, double p){
return Vector(A.x/p, A.y/p);
}
判断点是否在线段上
bool OnSegment(Point p, Point a1, Point a2){
return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) <= 0;
}
判断两线段是否相交
不允许在端点相交
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}
允许在端点处相交
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
//if判断控制是否允许线段在端点处相交,根据需要添加
if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
bool f1 = OnSegment(b1, a1, a2);
bool f2 = OnSegment(b2, a1, a2);
bool f3 = OnSegment(a1, b1, b2);
bool f4 = OnSegment(a2, b1, b2);
bool f = (f1|f2|f3|f4);
return f;
}
return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}
总结
struct Line{//直线定义
Point v, p;
Line(Point v, Point p):v(v), p(p) {}
Point point(double t){//返回点P = v + (p - v)*t
return v + (p - v)*t;
}
};
//计算两直线交点
//调用前需保证 Cross(v, w) != 0
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w){
Vector u = P-Q;
double t = Cross(w, u)/Cross(v, w);
return P+v*t;
}
//点P到直线AB距离公式
double DistanceToLine(Point P, Point A, Point B){
Vector v1 = B-A, v2 = P-A;
return fabs(Cross(v1, v2)/Length(v1));
}//不去绝对值,得到的是有向距离
//点P到线段AB距离公式
double DistanceToSegment(Point P, Point A, Point B){
if(A == B)
return Length(P-A);
Vector v1 = B-A, v2 = P-A, v3 = P-B;
if(dcmp(Dot(v1, v2)) < 0)
return Length(v2);
if(dcmp(Dot(v1, v3)) > 0)
return Length(v3);
return DistanceToLine(P, A, B);
}
//点P在直线AB上的投影点
Point GetLineProjection(Point P, Point A, Point B){
Vector v = B-A;
return A+v*(Dot(v, P-A)/Dot(v, v));
}
//判断p点是否在线段a1a2上
bool OnSegment(Point p, Point a1, Point a2){
return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0;
}
//判断两线段是否相交
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
//if判断控制是否允许线段在端点处相交,根据需要添加
if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
bool f1 = OnSegment(b1, a1, a2);
bool f2 = OnSegment(b2, a1, a2);
bool f3 = OnSegment(a1, b1, b2);
bool f4 = OnSegment(a2, b1, b2);
bool f = (f1|f2|f3|f4);
return f;
}
return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}