计算几何之凸包

大佬博客直通车

一.什么是凸包

二维平面上有若干个顶点,给定其坐标,凸包:能包裹住所有点的最小凸多面体
在这里插入图片描述
如图,以蓝色箭头为边的多面体就是该图的凸包

二.怎么求凸包–Graham算法

算法总体步骤:

根据凸包上的点只会向内旋转寻找下一个点的性质,循环判断下一个点是否满足该性质从而插入或删除点至凸包点集合

算法步骤如下:

0.设p[]为点,s[]为凸包点集合,cnt为凸包数量

1.找到一个y轴最小,有相同就找x最小的点作为凸包的起始点
因为该点一定被凸包经过

2.令该点为p[1],并作为原点,其他点根据到极点的极角排序从小到大,极角相同按极径排序从小到大
让极角小极径小的点作为
如何通过极角排序?
叉积!!!
从原点到p1,p2点,若其p0,p1,p2形成的叉积大于0,则p1逆时针选择到p2,即p1的极角小于p2

3.循环判断下一个点p[i]是否满足凸包性质,不满足就删除将凸包点集合最前面的点s[cnt]删除,并再次判断是否满足,直至满足凸包性质,再将那个点加入凸包点集合
如何判断是否向内旋转?
叉积!!!
从s[cnt]到s[cnt-1],p[i]点,若其形成的叉积大于等于0,则s[cnt-1]逆时针旋转至p[i],即向外旋转,不符合凸包性质,剔除s[cnt]点

完整代码如下

#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1e5+100;

struct point{
	double x,y;
}p[N],s[N];

int n,cnt;//凸包点数量 

double check(point p0,point p1,point p2){//叉积,用来判断向量的位置关系
	return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}//两向量x:p0->p1,y:p0->p2,若叉积大于0,则x逆时针旋转到y 

double dis(point p1,point p2){//两点间的距离 
	return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}

int cmp(point p1,point p2){//排序,按极角从小到大排序,极角相同按极径从小到大排序 
	double t=check(p[1],p1,p2);
	if(t>0)return 1;
	if(t==0&&dis(p[1],p1)<dis(p[1],p2))return 1;
	return 0; 
}
int main(){
	int n,t=1;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>p[i].x>>p[i].y;//输入部分 
	for(int i=2;i<=n;i++){
		if(p[i].y<p[t].y||(p[i].y==p[t].y&&p[i].x<p[t].x))t=i;//找到y轴最小的点,y轴相同找x轴最小的点,令它成为极点 
	}
	
	if(t!=1)swap(p[1],p[t]);//让p[1]成为极点 
	sort(p+2,p+n+1,cmp);//系统排序 
	
	s[++cnt]=p[1];
	for(int i=2;i<=n;i++){//Graham算法 
		while(cnt>1&&check(s[cnt],s[cnt-1],p[i])>=0)cnt--;//如果向内转,踢出 
		s[++cnt]=p[i];
	}
	s[cnt+1]=p[1];//闭合,最后一个点为起始点即极点p[1] 
	return 0;
} 

例题
模板题,最后求个距离和就可以,代码略

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值