首页 > 其他分享 >计算几何学习笔记

计算几何学习笔记

时间:2023-12-03 13:55:06浏览次数:30  
标签:node pre int 笔记 学习 vec 几何 三角形 include

叉乘(叉积)

定义(二维):

\[\vec{p_1} \times \vec{p_2} = x_1y_2-x_2y_1=-\vec{p_2}\times\vec{p_1} \]

性质:

若 \(\vec{p_2}\) 在 \(\vec{p_1}\) 的逆时针方向,则结果大于 0 。

若 \(\vec{p_2}\) 在 \(\vec{p_1}\) 的顺时针方向,则结果小于 0 。

若 \(\vec{p_2}\) 与 \(\vec{p_1}\) 共线,则结果为 0 。

应用

  1. 叉积等于两个向量对应平行四边形的有向面积,三角形面积等于叉积的一般
  2. 判断一条折线是向左拐还是向右拐
  3. 判断两个线段 ab 和 cd 是否相交:
    • \((\vec{ab}\times\vec{ac})\cdot(\vec{ab}\times\vec{ad})<0\) (点 c、d 分别在直线 ab 两侧) 并且 \((\vec{cd}\times\vec{ca})\cdot(\vec{cd}\times\vec{cb})<0\) (点 a、b 分别在直线 cd 两侧)
    • \(\vec{ab}\times\vec{ac}=0\) (某端点在另一条直线上) 且 \(min(x_a,x_b)<=x_c<=max(x_a,x_b) \&\& min(y_a,y_b)<=y_c<=max(y_a,y_b)\) (该端点在另一条线段上)
  4. 多边形的面积:取一个点(通常为原点)作为起点,以起点到各顶点的连线为边分割成的三角形的面积(带正负)之和。

求多边形的重心

关于重心的定义:物理意义上的重心

三角形的重心公式:

\[x_0=\frac{x_1+x_2+x_3}{3}\\ y_0=\frac{y_1+y_2+y_3}{3} \]

此公式若想应用到多边形,当且仅当多边形的重量全部分布在各个顶点上(公式内的系数为顶点的质量)。

质量均匀分布的多边形重心的求法:任取一个点与各个顶点连线组成三角形,各个三角形的重心的位置(三角形重心公式)和大小(三角形面积)可求。于是各三角形可以等价成各个重心,最后用加权的公式求解。

凸包

最小的凸多边形,满足覆盖了所有的点。

性质:凸包的所有点一定属于原来的点集。

格雷汉姆扫描法

取y值最小的点 \(p_0\) 作为原点。按照 \(p_0p_i\) 的斜率从小到大排序(用向量叉乘写 cmp 函数,放止精度问题)。开一个栈存凸包上的点,依次遍历每个点,检查栈顶的前两个元素与这个点构成的折线段是否“拐”向右侧(叉积 ≤ 0 ),是的话则不断弹出栈顶,直到折线段向左拐,此时将此点入栈。

时间复杂度为 \(O(n\log n)\)

贾维斯步进法

观察到确定原点后,斜率最小的点一定在凸包内(下一步一定向左转),那么可以每次找到斜率最小的点作为新的原点,不断更新凸包。

时间复杂度为 \(O(nh)\) ,h为凸包上的点个数(最坏情况为 n)(有一种死去的spfa的既视感)

旋转卡壳

用途:求凸包直径、用正方形框住所有点的最小面积等等。

核心思路:逆时针地遍历凸包上的边,对于每条边都找到离这条边最远的点,那么这时随着边的转动,对应的最远点也在逆时针旋转,不会有反向的情况。这样就保证了复杂度是O(n)的。

旋转卡壳 - OI Wiki yyds

习题

gxx's Problem

恶心了我足足两个周的题

先判断两个线段是否有交点,有的话输出交点,如果非整数则需要输出最简分数。

找两个不共线的线段的交点采用的是等底三角形面积之比等于高之比,进而再用相似三角形求算。详见此文章:CSDN博客

但是这个题的恶心之处在于需要判断两条线段是否有交点(一个还是无穷多个)以及是否共线。

总之就是分各种情况讨论,然后发现还是有的点wa了。

对拍正解,上千组数据也没拍出来。

最后在电梯里一想,会不会有线段是一个点的情况,试了试果然。

不得不说,好漂亮的数据点(微笑

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
long long cross(int x0,int y0,int x1,int y1){
	return 1ll*x0*y1-1ll*x1*y0;
}
long long direction(int x0,int y0,int x1,int y1,int x2,int y2){
	return cross(x1-x0,y1-y0,x2-x0,y2-y0);
}
bool onseg(int xa,int ya,int xb,int yb,int xc,int yc){
	return min(xa,xb)<=xc&&xc<=max(xa,xb)&&min(ya,yb)<=yc&&yc<=max(ya,yb);
}
bool inseg(int xa,int ya,int xb,int yb,int xc,int yc){
	return min(xa,xb)<xc&&xc<max(xa,xb)||min(ya,yb)<yc&&yc<max(ya,yb);
}
int intersection(int xa,int ya,int xb,int yb,int xc,int yc,int xd,int yd){
	long long d1=direction(xa,ya,xb,yb,xc,yc);
	long long d2=direction(xa,ya,xb,yb,xd,yd);
	long long d3=direction(xc,yc,xd,yd,xa,ya);
	long long d4=direction(xc,yc,xd,yd,xb,yb);
	if(d1*d2<0&&d3*d4<0) return 1;
	if(d1==0&&d2==0){
		if(onseg(xa,ya,xb,yb,xc,yc)&&onseg(xa,ya,xb,yb,xd,yd)) return -1;
		if(onseg(xc,yc,xd,yd,xa,ya)&&onseg(xc,yc,xd,yd,xb,yb)) return -1;
		if(inseg(xa,ya,xb,yb,xc,yc)||inseg(xa,ya,xb,yb,xd,yd)) return -1;
		if(inseg(xc,yc,xd,yd,xa,ya)||inseg(xc,yc,xd,yd,xb,yb)) return -1;
		if(onseg(xa,ya,xb,yb,xc,yc)||onseg(xa,ya,xb,yb,xd,yd)||onseg(xc,yc,xd,yd,xa,ya)||onseg(xc,yc,xd,yd,xb,yb)) return 2;
		return 0;
	}
	if(d1==0&&onseg(xa,ya,xb,yb,xc,yc)) return 1;
	if(d2==0&&onseg(xa,ya,xb,yb,xd,yd)) return 1;
	if(d3==0&&onseg(xc,yc,xd,yd,xa,ya)) return 1;
	if(d4==0&&onseg(xc,yc,xd,yd,xb,yb)) return 1;
	return 0;
}
long long gcd(long long a,long long b){
	if(b==0) return a;
	return gcd(b,a%b);
}
void Prin(long long a,long long b){
	int f=1;
	if(a<0) f*=-1,a=-a;
	if(b<0) f*=-1,b=-b; 
	long long c=gcd(a,b);
	a/=c;b/=c;
	if(b==1) printf("%lld",f*a);
	else printf("%lld/%lld",f*a,b);
}
void putinter(int x1,int y1,int px1,int py1,int x2,int y2,int px2,int py2){
	int px3=x1-x2,py3=y1-y2;
	long long fr1=cross(px2,py2,px3,py3),fr2=cross(px1,py1,px2,py2);
	Prin(1ll*x1*fr2+1ll*fr1*px1,fr2);
	putchar(' ');
	Prin(1ll*y1*fr2+1ll*py1*fr1,fr2);
	puts("");
}
signed main()
{
	int T=read();
	while(T--){
		int xa=read(),ya=read(),xb=read(),yb=read();
		int xc=read(),yc=read(),xd=read(),yd=read();
		int num=intersection(xa,ya,xb,yb,xc,yc,xd,yd);
		if(xa==xb&&ya==yb){
			if(onseg(xc,yc,xd,yd,xa,ya)) printf("1\n%lld %lld\n",xa,ya);
			else puts("0"); 
			continue;
		}
		if(xc==xd&&yc==yd){
			if(onseg(xa,ya,xb,yb,xc,yc)) printf("1\n%lld %lld\n",xc,yc);
			else puts("0"); 
			continue;
		}
		if(num==0) puts("0");
		else if(num==-1) puts("INF");
		else{
			puts("1");
			if(num==1) putinter(xa,ya,xb-xa,yb-ya,xc,yc,xd-xc,yd-yc);
			else{
				if(onseg(xa,ya,xb,yb,xc,yc)) printf("%lld %lld\n",xc,yc);
				else printf("%lld %lld\n",xd,yd);
			}
		}
	}
    return 0;
}

Surround the Trees

凸包板子题

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=105;
struct node{
	int x,y;
	node operator +(const node &b){
		node c;
		c.x=x+b.x;
		c.y=y+b.y;
		return c;
	}
	node operator -(const node &b){
		node c;
		c.x=x-b.x;
		c.y=y-b.y;
		return c;
	}
}a[maxn];
node ans[maxn];
stack<node> s;
int cross(node a,node b){
	return a.x*b.y-a.y*b.x;
}
bool cmp1(node a,node b){
	return a.y<b.y;
}
bool cmp2(node b,node c){
	int cr=cross(b-a[1],c-a[1]);
	return cr!=0?cr>0:b.x<c.x;
}
double cal(node a,node b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
	int n=read();
	while(n){
		while(!s.empty()) s.pop();
		for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
		sort(a+1,a+n+1,cmp1);
		sort(a+2,a+n+1,cmp2);
		for(int i=1;i<=n;i++){
			while(s.size()>=2){
				node pre=s.top();s.pop();
				node ppre=s.top();
				if(cross(pre-ppre,a[i]-pre)>0){
					s.push(pre);
					break;
				}
			}
			s.push(a[i]);
		}
		int cnt=0;
		double anss=0;
		while(!s.empty()){
			ans[++cnt]=s.top();
			s.pop();
		}
		for(int i=1;i<cnt;i++) anss+=cal(ans[i],ans[i+1]);
		if(cnt>2) anss+=cal(ans[cnt],ans[1]);
		printf("%.2lf\n",anss);
		n=read();
	}
    return 0;
}

最大三角形

凸包上旋转卡壳板子题。

易得最大的三角形的顶点一定在凸包上。所以先 \(O(n\log n)\) 求出凸包。

然后类比找直径的过程,易得当三角形底边跨的点数一定时,对面的顶点一定也满足凸的性质。

所以最外层枚举三角形底边跨的点数 len,然后模拟指针指向对面的最远点,不断更新答案。

对于每一个 len 时间复杂度为 \(O(n)\) 的,所以总复杂度为 \(O(n^2)\) 。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<iomanip>
#include<ctime>
#include<stack>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!(c>='0'&&c<='9')) {if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=200005;
int n;
struct node{
	int x,y;
	node operator +(const node &b)const{
		return {x+b.x,y+b.y};
	}
	node operator -(const node &b)const{
		return {x-b.x,y-b.y};
	}
}a[maxn];
int cross(node a,node b){
	return a.x*b.y-a.y*b.x;
}
bool cmp1(node a,node b){
	return a.y<b.y;
}
bool cmp2(node aa,node bb){
	return cross(aa-a[1],bb-a[1])>0;
}
double S(node a,node b){
	return 0.5*abs(cross(a,b));
}
int main()
{
	while(scanf("%d",&n)!=EOF){
		for(int i=1;i<=n;i++){
			a[i].x=read(),a[i].y=read();
		}
		sort(a+1,a+n+1,cmp1);
		sort(a+2,a+n+1,cmp2);
		stack<node> q;
		for(int i=1;i<=n;i++){
			while(q.size()>=2){
				node pre=q.top();q.pop();
				node pree=q.top();
				if(cross(pre-pree,a[i]-pre)>0){
					q.push(pre);
					break;
				}
			}
			q.push(a[i]);
		}
		int cnt=0;
		while(!q.empty()){
			a[++cnt]=q.top();
			q.pop();
		}
		for(int i=1;i<=cnt;i++){
			a[i+cnt*2]=a[i+cnt]=a[i];
		}
		double ans=0;
		for(int len=1;len<cnt;len++){
			int now=len+2;
			for(int i=1;i<=cnt;i++){
				int j=i+len;
				while(S(a[j]-a[i],a[now]-a[i])<S(a[j]-a[i],a[now+1]-a[i])) now++;
				ans=max(ans,S(a[j]-a[i],a[now]-a[i]));
			}
		}
		printf("%.2lf\n",ans);
	}
    return 0;
}

标签:node,pre,int,笔记,学习,vec,几何,三角形,include
From: https://www.cnblogs.com/yinyuqin/p/17872922.html

相关文章

  • 学习笔记12
    一、苏格拉底挑战二、遇见的问题三、实践过程......
  • 学习笔记十二
    MySQL数据库系统一、MySQL简介MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。MySQL所使用的SQL语言是用于访问数据库的最常用标准化语言。MySQL软件采用了双授权政策,分为社区版和商业......
  • 商用密码的产业发展及应用创新学习笔记
    商用密码的产业发展及应用创新讲解人:北京数字认证股份有限公司:林雪焰共建可信任的数字世界密码技术数字信任(DigitalTrust)数据安全(DataSecurity)数字身份管理(DigitalIdentityManagement)以密码技术为核心的自主知识产权产品及服务1.身份与访问管理2.密码基......
  • 学习笔记12——20211303
    一、学习任务自学教材第14章,提交学习笔记(10分),评分标准如下1.知识点归纳以及自己最有收获的内容,选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容(4分)“我在学***X知识点,请你以苏格拉底的方式对我进行提问,一次一个问题”核心是要求GPT:......
  • 2023-2024-1 20232314《网络空间安全导论》第四周学习总结
    教材内容学习总结 教材学习中的问题和解决过程问题1:对于威胁建模的具体概念理解解决方案:询问Chatgpt,得知威胁建模是一种基于工程和风险的方法,旨在识别、评估和管理安全威胁,以开发和部署符合企业组织安全和风险目标的更好软件和IT系统。这个过程可以分为几个阶段:威胁识别、......
  • 学习笔记12
    学习笔记12教材知识点总结14.1MySQL简介关系数据库系统:数据存储在表中,表由多个行和列组成表之间互相关联,关系结构使得可在表上查询来检索信息并修改数据库中的数据MySQL:开源数据库管理系统,有服务器和客户机组成14.2安装MySQLUbuntuLinux:sudoapt-getinsta......
  • Unity学习笔记--数据持久化Json
    JSON相关json是国际通用语言,可以跨平台(游戏,软件,网页,不同OS)使用,json语法较为简单,使用更广泛。json使用键值对来存储。认识json文件//注意字典类型存储时,键是以string类型存储的需要添加“”{"name":"TonyChang","age":21,"sex":true,"Float":2.5,"arrarys"......
  • openGauss学习笔记-139 openGauss 数据库运维-例行维护-检查应用连接数
    openGauss学习笔记-139openGauss数据库运维-例行维护-检查应用连接数如果应用程序与数据库的连接数超过最大值,则新的连接无法建立。建议每天检查连接数,及时释放空闲的连接或者增加最大连接数。139.1操作步骤以操作系统用户omm登录数据库主节点。使用如下命令连接数据库......
  • 2023-2024-1 20232327《网络空间安全导论》第四周学习总结
    2023-2024-120232327《网络空间安全导论》第三周学习总结教材学习内容总结1.还原论——把大系统分解为小系统,整体论——把系统看成是一个统一的整体;2.攻击:把威胁付诸实现的行为;3.威胁建模:标识潜在安全威胁并审视风险缓解途径的过程;4.访问控制:防止系统中出现不按规矩对资源进......
  • 2023-2024-1 20231417 《计算机基础与程序设计》第十周学习总结
    2023-2024-120231417《计算机基础与程序设计》第十周学习总结作业信息这个作业属于哪个课程2023-2024-1-计算机基础与程序设计这个作业要求在哪里2023-2024-1计算机基础与程序设计第十周作业这个作业的目标自学计算机科学概论第12,13,14章,《C语言程序设计》第9章......