点和向量
表示法:
点用横纵坐标来表示,所以我们定义一个结构体
而向量可以用一个点表示,所以就直接当点来用
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 - (Point A,Point B) {
return Vector(A.x-B.x,A.y-B.y);
}//点-点=向量
Vector operator * (Vector A,double x) {
return Vector(A.x*x,A.y*x);
}//向量*一个数=向量
Vector operator / (Vector A,double x) {
return Vector(A.x/x,A.y/x);
}//向量/一个数=向量
点积
点积也是高中学的向量的数量级,这一部分有很公式,可以用于求两个向量夹角的大小(参见数学必修四课本)
求点积也用的是书中最朴素的算法
double operator * (Vector A,Vector B) {
return A.x*B.x+A.y*B.y;
}//点积
double len(Vector A) {
return sqrt(A*A);
}//向量的长度等于sqrt(A,A)
double jiao(Vector A,Vector B) {
return acos((A*B)/len(A)/len(B));
}//向量的夹角等于acos(A·B/|A|/|B|)
其正负是由夹角的大小决定的
点积满足交换律
a
⃗
⋅
b
⃗
=
b
⃗
⋅
a
⃗
\vec a \cdot \vec b = \vec b \cdot \vec a
a⋅b=b⋅a
叉积
叉积通常用于求多边形面积以及判断两个向量的位置关系
double operator ^ (Vector A,Vector B) {
return A.x*B.y-A.y*B.x;
}//叉积
double S(Vector A,Vector B) {
return (A^B)/2;
}//面积是两个向量叉积的二分之一
叉积的正负是由两个向量的位置关系决定的。
叉积不满足交换律
a
⃗
⋅
b
⃗
=
−
b
⃗
⋅
a
⃗
\vec a \cdot \vec b = - \vec b \cdot \vec a
a⋅b=−b⋅a
旋转
将向量A旋转rad度
Vector Rotate(Vector A,double rad) {
return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
直线
由两点确定一条直线,所以我们用两个点表示直线
struct line {
Point a,b;
double ang;
line() {}
line(Point a,Point b):a(a),b(b){
ang=atan2(b.y-a.y,b.x-a.x);
}
/*
atan2是一个函数,在C语言里返回的是指方位角,也可以理解为计算复数 x+yi 的辐角
计算时atan2 比 atan 稳定。
*/
};
bool operator < (line A,line B) {
return sige(A.ang-B.ang)==0?sign((A.a-A.b)^(B.a-B.b))>0:sign(A.ang-B.ang)<0;
}//向量左侧求交,所以极角相同时靠左的更优,把优的放在后面,方便之后的操作
求交点:
Point inter (line A,line B) {
Point p1=A.p,p2=B.p,v1=A.v,v2=B.v;
v1=v1-p1;
v2=v2-p2;
Point u=p2-p1;
Point p=p2+((u^v1)/(v1^v2))*v2;
return p;
}
凸包
学习过斜率优化的童鞋们应该对凸包都不陌生,这里就不做详细的介绍了
手动上代码 P2742 【模板】二维凸包
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N=100010;
const double eps=1e-8;
struct vector {
double x,y;
vector(double x=0,double y=0):x(x),y(y) {};
};
#define 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 k) {return vector(a.x*k,a.y* k);}
vector operator / (vector a,double k) {return vector(a.x/k,a.y/k);}
double operator * (vector a,vector b) {return a.x*b.x+a.y*b.y;}
double operator ^ (vector a,vector b) {return a.x*b.y-b.x*a.y;}
vector d[N],hull[N];
bool operator < (point a,point b) {return a.x==b.x?a.y<b.y:a.x<b.x;}
int n,m;
double len(vector a) {return sqrt(a.x*a.x+a.y*a.y);}
void get_hull() {
m=2;
hull[1]=d[1],hull[2]=d[2];
for(int i= 3;i<=n;++i) {
while(m>1&&(((hull[m]-hull[m-1])^(d[i]-hull[m-1]))-eps<0)) --m;
hull[++m]=d[i];
}
int k=m;
for(int i=n-1;i>=1;--i) {
while(m>k&&(((hull[m]-hull[m-1])^(d[i]-hull[m-1]))-eps<0)) --m;
hull[++m]=d[i];
}
}
int main() {
cin>>n;
for(int i=1; i<=n; ++i)
cin>>d[i].x>>d[i].y;
sort(d+1,d+n+1) ;
get_hull();
double ans;
for(int i=1;i<m;++i )
ans+=len(hull[i]-hull[i+1]);
printf("%.2lf\n",ans);
return 0;
}
更多的内容可以手动跳转一下–>凸包入门题目