凸包
今天看了一下凸包,自己理解的也不是很深,在这里说说自己的理解
凸包:在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。
用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能 包含点集中所有的点。--百度百科
这几个用蓝线连起来的红点就组成了一个凸包
![](http://pic002.cnblogs.com/images/2011/287127/2011080514225666.jpg)
如何求这个凸包呢
1.首先我们先对这些点进行极角排序
极角排序:找y最小的点,如果y最小的点有好几个,那就找x最小的点,相同的点排除掉,把这个点做为 基点H,接下来所有的点针对该点的射线,按角度由小到大,若相同按距离由近到远来排序
如何判断角度的大小,需要左转判定,假如有两个点p1,p2,求出向量<p1,H> (x1,y1)和<p2,H> (x2,y2),
如果 x1*y2-x2*y1>0 说明p1到p2左转
排序后应该是这样
2.排完序,我们就可以从基点开始找凸包了(Graham算法)
1.把排完序的点p0,p1,p2入栈
2.判断p[i]与栈内的stack[top],stack[top-1],p[i]到stack[top]是否左转了,如果是,出栈,直到找到
p[i]相对于栈内没有左转的时候,把p[i]进栈
过程大概是这样的
第一步 0 , 1 ,2入栈 第二步 1到3左转,2出栈
![](https://img-blog.csdn.net/20160823153114601?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第三步 1到4右转,4入栈 最后遍历完成,凸包形成
![](https://img-blog.csdn.net/20160823153744670?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
第一步 0 , 1 ,2入栈 第二步 1到3左转,2出栈
第三步 1到4右转,4入栈 最后遍历完成,凸包形成
3.遍历完后stack里存的凸包的点,top+1代表点的个数
下面是代码
struct node
{
long long x,y;
}q[51234],stack1[51234];
int n,top;
long long dist(node p1,node p2) //两点距离的平方
{
return (p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);
}
long long mult(node p1,node p2,node p0) //判断是否左转
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int cmp(node p1,node p2) //极角排序的比较函数
{
if(mult(p1,p2,q[0])>0)
return 1;
else if(mult(p1,p2,q[0])==0 && dist(p1,q[0])<dist(p2,q[0])) //相等的按距离近的
return 1;
return 0;
}
void Gramham()
{
int i,k=0;
for(i=0;i<n;i++)
{
if(q[i].y<q[k].y || (q[i].y==q[k].y && q[i].x<q[k].x)) //找y最小的点,y相等找x最小的点
k=i;
}
node tep;
tep=q[0];
q[0]=q[k];
q[k]=tep;
sort(q+1,q+n,cmp);
stack1[0]=q[0];
stack1[1]=q[1];
stack1[2]=q[2];
top=2;
for(i=3;i<n;i++)
{
while(top>1 && mult(q[i],stack1[top],stack1[top-1])>=0) //是否左转,是继续判断,不是,就入栈
top--;
stack1[++top]=q[i];
}
}
如有错误,望指出^_^