小蒟蒻的计算几何学习初步

12 篇文章 0 订阅
2 篇文章 0 订阅

点和向量

表示法:

点用横纵坐标来表示,所以我们定义一个结构体
而向量可以用一个点表示,所以就直接当点来用

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;
}

更多的内容可以手动跳转一下–>凸包入门题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值