凸包

    凸包是计算几何中的一个基本概念。在竞赛中,很少单独考察凸包,但求凸包是很多题目求解的一个关键性步骤。

    1)凸包的性质

        给定一个点集,凸包是能够包围所有点的最小凸多边形。”凸包边上的点,称为凸包点,其余点称为凸包内点“(引自何援军著《几何计算》)

        凸包有一些区别于普通多边形的重要性质:

        1.所有的顶点均在任何一条凸包边所在直线的一侧,如果逆时针遍历凸包的边,则对每条边,所有点均在其左侧。

        2.从任一点出发,沿逆时针遍历凸包,总是向左转,沿顺时针遍历凸包,总是向右转(即叉乘的符号在沿同一方向运动时是不变的)。

        3.凸包对凸包点排序,即选定一条边,凸包上的点依次与该边所在直线的距离成单峰函数。

    2)凸包求法

        经常会遇到这样的问题:给定平面上的一些点,求这些点对应的凸包。

        此处暂介绍一种方法:Graham扫描法,还有其他方法,这里不再介绍。

        步骤如下:

        1.将点按照x坐标排序,x坐标相同就按y坐标排序。

        2.第一个点必定是凸包中的点,将其压入栈S中。

        3.对下一个点进行判断,如果栈内元素小于2个,则将该点直接加入栈中;否则,进行叉积判断。如果是进行逆时针判断,只要遇到向右转的情况,就从栈中弹出一个点,直到栈中只剩一个点或者出现左转。重复此步骤,直到n个点全部遍历完毕。

        4.从n开始,向前遍历,遍历方法如3,直到遍历到第一个点。

        整体过程如下图所示:

       



这时遇到右转,将P3弹出。



再次遇到右转情况,弹出P4。




特别提醒:如果出现三点共线的情况,最好将中间的点删去,可以让复杂度稍微小一点。


出现右转,将P5弹出。



右转,弹出P4。



回到起点,这时栈S中的元素:P1,P2,P5,P6,P3,P1,这就是整个凸包的凸包点的集合。

代码实现如下:

point s[N];                                      //运行结束时,凸包点按顺序存于s中,n为凸包顶点的个数 
double cp(point a,point b,point o)               //叉积 
{
	return (a-o)*(b-o);
}
void convex(point *p,int &n)                     //参数p为输入点,n为输入点个数 
{
	sort(p,p+n);                                 //将点按x坐标排序,如果x相同按y坐标排序 
	int i,j,r,top,m;
	s[0]=p[0];s[1]=p[1];top=1;
	for(i=2;i<n;++i)                             //从前向后扫描 
	{
		while(top>0&&cp(p[i],s[top],s[top-1])>=0)
		  top--;
		top++;s[top]=p[i];
	}
	m=top;                                       //记录当前栈s里元素的个数 
	top++;s[top]=p[n-2];
	for(i=n-3;i>=0;i--)                          //从后向前扫描 
	{
		while(top>m&&cp(p[i],s[top],s[top-1])>=0)
		  top--;
		top++;s[top]=p[i];
	}
	top--;
	m=top+1;
}

【习题推荐】

HDU 3629

HDU 1348

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/80976917
今日推荐