【ACM算法讲堂之 - 计算几何基础】:【点积和叉积】(附一些模板)

计算几何是算法竞赛的一大块,而叉积是计算机和的基础。

首先叉积是计算说向量之间的叉积,那么我们可以这样定义向量,以及向量的运算符重载。

 

struct Point
{
    double x,y;
    Point(double x=0,double y=0):x(x),y(y) {}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B) { return Vector(A.x+B.x,A.y+B.y); }
Vector operator - (Vector A,Vector 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 operator < (const Point& a,const Point& b)
{
    return a.x<b.x || (a.x==b.x && a.y<b.y);
}
int dcmp(double x)  //
{
    if(fabs(x)<esp) return 0;
    else return x<0?-1:1;
}
bool operator == (const Point& a,const Point& b)
{
    return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y)==0;
}

 

首先在二维坐标下介绍一些定义:

点:A(x1,y1),B(x2,y2)

向量:向量AB=( x2 - x1 , y2 - y1 )= ( x ,  y );

向量的模 |AB| = sqrt ( x*x+y*y );

 

向量的点积: 结果为 x1*x2 + y1*y2。

点积的结果是一个数值。

点积的集合意义:我们以向量 a 向向量 b 做垂线,则 | a | * cos(a,b)为 a 在向量 b 上的投影,即点积是一个向量在另一个向量上的投影乘以另一个向量。且满足交换律

应用:可以根据集合意义求两向量的夹角,cos(a,b) =( 向量a * 向量b ) / (| a | * | b |) =  x1*x2 + y1*y2 / (| a | * | b |)

 

 

向量的叉积: 结果为 x1*y2-x2*y1

叉积的结果也是一个向量,是垂直于向量a,b所形成的平面,如果看成三维坐标的话是在 z 轴上,上面结果是它的模。

方向判定:右手定则,(右手半握,大拇指垂直向上,四指右向量a握向b,大拇指的方向就是叉积的方向)

叉积的集合意义:1:其结果是a和b为相邻边形成平行四边形的面积。

2:结果有正有负,有sin(a,b)可知和其夹角有关,夹角大于180°为负值。

3:叉积不满足交换律

应用:

1:通过结果的正负判断两矢量之间的顺逆时针关系

若 a x b > 0表示a在b的顺时针方向上

若 a x b < 0表示a在b的逆时针方向上

若 a x b == 0表示a在b共线,但不确定方向是否相同

 

2:判断折线拐向,可转化为判断第三点在前两的形成直线的顺逆时针方向,然后判断拐向。

3:判断一个点在一条直线的那一侧,同样上面的方法。

4:判断点是否在线段上,可利用叉乘首先判断是否共线,然后在判断是否在其上。

5:判断两条直线是否想交(跨立实验)

根据判断点在直线那一侧我们可以判断一个线段的上的两点分别在另一个线段的两侧,当然这是不够的,因为我们画图发现这样只能够让直线想交,而不是线段,所以我们还要对另一条线段也进行相同的判断就ok。

///计算点积,及向量长度,及向量夹角
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); }
//计算叉积,向量逆时针旋转,两线段是否想交
double Cross(Vector A,Vector B) { return (A.x*B.y-A.y*B.x); }
double Area2(Vector A,Vector B,Vector C)  { return Cross(B-A,C-A); }
Vector Rotate(Vector A,double rad)
{
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
bool Converxline(Vector A,Vector B,Vector C,Vector D)
{
    //共线或平行
    if((Area2(A,B,C)==0&&Area2(A,B,D)==0) || Area2(A,B,C)*Area2(A,B,D)>0||Area2(C,D,A)*Area2(C,D,B)>0)
        return false;
    else
        return true;
}

转自https://blog.csdn.net/y990041769/article/details/38258761

模板如下:

const double eps = 1e-10;
//考虑误差的加法
double add(double a, double b) {
    if(fabs(a + b) < eps * (fabs(a) + fabs(b))) return 0;
    return a + b;
}
//考虑误差的与0比较
int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    else return x<0?-1:1;
}
struct P {
    double x, y;
    P(){}
    P(double x, double y) :x(x), y(y){}
    bool operator == (P p) {
        return dcmp(x - p.x) == 0 && dcmp(y - p.y) == 0;
    }
    P operator + (P p) {
        return P(add(x, p.x), add(y, p.y));
    }
    P operator - (P p) {
        return P(add(x, -p.x), add(y, -p.y));
    }
    P operator * (double p) {
        return P(x * p, y * p);
    }
    P operator / (double p) {
        return P(x / p, y / p);
    }
    //点积
    double dot(P p) {
        return add(x * p.x, y * p.y);
    }
    //叉积
    double cross(P p) {
        return add(x * p.y, -y * p.x);
    }
};
typedef P Vector;
//向量逆时针旋转
Vector Rotate(Vector a,double rad)  {
    return Vector(a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad));
}
//向量的模
double len(Vector a){
    return sqrt(a.dot(a));
}
//两向量的夹角
double angle(Vector a, Vector b) {
    return acos(a.dot(b) / len(a) / len(b));
}
//绝对值为三点确定的三角形的面积的两倍
double area2(Vector a, Vector b, Vector c) {
    return (b - a).cross(c - a);
}
//判断p点是否在线段a-b上
bool on_seg(P p, Vector a, Vector b) {
    return (a - p).cross(b - p) == 0 && (a - p).dot(b - p) <= 0;
}
//判断两条线段是否相交
bool intersect(Vector a, Vector b, Vector c, Vector d) {
    if(area2(a, b, c) == 0 && area2(a, b, d) == 0
    || area2(a, b, c) * area2(a, b, d) > 0
    || area2(c, d, a) * area2(c, d, b) > 0) return false;
    return true;
}
//判断两条线段是否有交点
bool _intersect(Vector a, Vector b, Vector c, Vector d) {
    if(area2(a, b, c) == 0 && area2(a, b, d) == 0 && !on_seg(a, c, d) && !on_seg(b, c, d)
    || area2(a, b, c) * area2(a, b, d) > 0
    || area2(c, d, a) * area2(c, d, b) > 0) return false;
    return true;
}

 

没有更多推荐了,返回首页