凸包_Graham算法

凸包问题-求在一群散乱的点中,找出一定的点通过连线可以将所有的点给囊括其中——也就是求能包括这所有点的最大周长。

算法步骤:

第一步:首先找出y值最小的点P0,因为可以确定的是如果一个点的y值最小那么他一定在凸包上。

第二步:以这个点P0未基准,给其他的点进行排序,(按照极值从小到大排序)

第三步:将P0,P1,P2三个点纳入凸包里,开始扫描,如果p0-p1 p1-p2的叉积大于0 表示 p0 p1 p2之间的夹角小于180度,那么p1就是凸包上的点,否则,p1就不是凸包上的点,然后继续往下扫描。

 

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int n;  // 表示点的个数
struct node {
	int x,y;
} vex[1000]; //点
node invex[1000];
int xx,yy;
int cmp(node a,node b) {
	return a.y<b.y;
}   //第一次排序
int cmp1(node a,node b) {
	if(atan2(a.y-yy,a.x-xx)!=atan2(b.y-yy,b.x-xx))
		return (atan2(a.y-yy,a.x-xx))<(atan2(b.y-yy,b.x-xx));
	return a.x<b.x;
}    //第二次排序


int cross(node a,node b,node c) {  //计算 p0 p1 p2 之间的叉积

	return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);

}

double dis(node a, node b) {   //计算距离

	return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));
}

int main() {
	scanf("%d",&n);
	for(int i=0; i<n; i++) {
		scanf("%d%d",&vex[i].x,&vex[i].y);
	}
	sort(vex,vex+n,cmp); //第一次排序找出y值最小的点
	invex[0]=vex[0];     //进入凸包的点的集合
	xx = invex[0].x;     
	yy = invex[0].y;
	sort(vex+1,vex+n,cmp1); //根据p0来进行第二次排序,以极值排序
	invex[1]=vex[1];        // p1 进入
	int top = 1;
	for(int i=2; i<n; i++) {
		while(top>=1 && cross(invex[top-1],invex[top],vex[i])<0) {//如果叉积小于0则不能进入
			top--;
		}
		invex[++top]=vex[i];
	}
	double s = 0;
	for(int i=1; i<n; i++) {   //计算凸包的周长
		s+=dis(invex[i-1],invex[i]); 
	}
	s+=dis(invex[0],invex[top]);  //最后invex[0] invex[top] 整个凸包连在一起
	printf("%.2lf\n",s);
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值