一.什么是凸包
二维平面上有若干个顶点,给定其坐标,凸包:能包裹住所有点的最小凸多面体
如图,以蓝色箭头为边的多面体就是该图的凸包
二.怎么求凸包–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;
}
例题
模板题,最后求个距离和就可以,代码略