原创 首页 算法

凸包:Graham 扫描

LinJHS 1

前言

凸包(Convex Hull)是一个计算几何(图形学)中的概念。

在一个实数向量空间 V 中,对于给定集合 X ,所有包含 X 的凸集的交集 S 被称为 X 的凸包。 X 的凸包可以用 X 内所有点 (X_1,...,X_n) 的凸组合来构造.

在二维欧几里得空间中,凸包可想象为一条刚好包着所有点的橡皮圈。

用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。

求法

#include <bits/stdc++.h>
using namespace std;

/*
题目描述:给定若干个点,求凸包的周长 
解法:从左下角开始逆时针找到所有的点 
*/ 
const int N=1050;//点数 

struct Point{
    int x,y;
}p[N],s[N];//p存放输入的点,s存放凸包的点(从0开始存哦) 

int n;//总点数 
int top;//凸包的点数-1,也就是最后一个点的位置 

int cross(Point a,Point b,Point c)//向量叉乘,绝对值大小为构成的平行四边形面积 
{
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

double dis(Point a,Point b)//两点间距离 
{
	return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool cmp(Point a,Point b)//使所有点按对于p0逆时针排列,如果共线的话距离近的排在前面 
{
	int t=cross(p[0],a,b);//共线-0,对于p0来说,a在b顺时针方向-正,a在b逆时针方向-负 
	if(t>0 || t==0 && dis(p[0],a)<dis(p[0],b))
		return true;
	else
		return false;
}

void init(int n)
{
	scanf("%d%d",&p[0].x,&p[0].y);
	Point p0={p[0].x,p[0].y};//p0用于存放左下角的点 
	int k=0;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&p[i].x,&p[i].y);
		if(p[i].y<p0.y || p[i].y==p0.y && p[i].x<p0.x)//找到左下角的点 
		{
			p0=p[i];
			k=i;
		}
	}
	p[k]=p[0];
	p[0]=p0;//把左下角的点移到最前面 
	sort(p+1,p+n,cmp);//剩下的点排序 
}

void graham(int n)
{
	if(n==1)//如果只有一个点,那就是一个点 
	{
		top=0;
		s[0]=p[0];
	}
	else if(n==2)//同理,两个点 
	{
		top=1;
		s[0]=p[0];
		s[1]=p[1];
	}
	else//不止两个点 
	{
		top=1;
		s[0]=p[0];
		s[1]=p[1];
		for(int i=2;i<n;i++)
		{
			while(top>0 && cross(s[top-1],s[top],p[i])<=0)//与新点不构成逆时针也就是凸包的话 
				top--;//删掉最后一个点 
			s[++top]=p[i];//加入新的点 
		}
	}
}

int main()
{
	while(scanf("%d",&n)>0 && n)
	{
		init(n);
		graham(n);
		double ans=0;
		for(int i=1;i<=top;i++)
		{
			ans+=dis(s[i],s[i-1]);
		}
		ans+=dis(s[0],s[top]);
		if(n==2)
		{
			ans/=2;
		}
		printf("%.2lf\n",ans);
	}
	return 0;
}
  • 以左下角的点为初始点,剩下的点按照以初始点为中心逆时针的方向进行排序(如果共线的话距离初始点近的排在前面,使用向量叉乘判断)。

  • 特判只有一个点或者两个点的情况。

  • 不止两个点的话,按顺序枚举每个点作为新点,如果最后两个点与新点不构成逆时针(用向量叉乘判断)也就是凸包的话,删掉最后一个点,直到找到满足条件的新点,将新点加入。


注:部分资料来源于百度百科

分享
如果这篇文章帮到你,可以请我喝一杯茶。

微信扫码打开

请我喝杯茶

如果这篇文章帮到你,可以请我喝一杯茶。

微信收款码
在商城请我一杯