凸包指的是一个点集中的最小凸多边形,且其包含了所有点集内的点;简单地说,就是点集最外侧的点构成的凸多边形。求凸包有两种方法:卷包裹法和Graham-Scan算法。
1、卷包裹法:
每次找出极角最小的边,通过它到达下一点,重复这一过程直到回到原点;具体过程如下:
(1)找出左下角的点(以横纵坐标为第一第二关键字,可以找x最小的,x相同则找y最小的),显然这个点一定为凸包上的一个顶点;
(2)以(1)中找出的点为原点,选出任意一条边(起点为原点),与所有其它边进行对比直至找到极角最小的边(通过叉乘比较,详见计算几何板块);
(3)通过该边找到下一个点,重复(2)中过程,直到回到原点,这个序列就是凸包序列。
效率分析:每找到一个点,我们都要枚举一遍其他所有点,因此效率是。
部分代码:
int dist(int x1,int y1,int x2,int y2) //求距离
{
return int(pow(double(x2-x1),2)+pow(double(y2-y1),2));
}
int mul_cross(int x1,int y1,int x2,int y2) //求叉乘
{
return(x1*y2-x2*y1);
}
void find_1() //找左下角的点
{
x[0]=2147483647;
y[0]=2147483647;
root=0;
for (int i=1;i<=n;i++)
if (x[i]
2、Graham-Scan算法:
以左下角的点为原点,按逆时针将边排序,用栈存凸包;过程如下:
(1)找出左下角的点;
(2)以(1)中找出的点作为原点,将其余点逆时针排序(即极角按从小到大排序);
(3)将原点以及排序后第一个点压入栈内;
(4)设栈顶为top,按排序后的顺序逆时针枚举其他所有点;在考虑某个点时,要用类似单调队列的方法,不断比较该点与栈中top-1连的边和栈顶的点与栈中top-1连的边,若其更靠外侧(即叉乘小于0),则将栈顶元素弹出栈(top--),直到其更靠内侧,然后把该点压入栈。
效率分析:排序的时间复杂度为,因为每个点最多入栈一次,所以效率为
。
部分代码:
int multiplication_cross(int x1,int y1,int x2,int y2) //求叉乘
{
return (x1*y2-x2*y1);
}
void swap(int i,int j) //交换,把左下角的点放在数组第一位
{
int k=x[i];
x[i]=x[j];
x[j]=k;
k=y[i];
y[i]=y[j];
y[j]=k;
}
double distance_self(int i,int j) //求两点间距离
{
return sqrt(pow(double(x[i]-x[j]),2)+pow(double(y[i]-y[j]),2));
}
void qs(int l,int r) //排序
{
int i=l;
int j=r;
int mx=x[(l+r)/2];
int my=y[(l+r)/2];
while (i<=j)
{
while ((multiplication_cross(x[i]-x[1],y[i]-y[1],mx-x[1],my-y[1])>0||(multiplication_cross(x[i]-x[1],y[i]-y[1],mx-x[1],my-y[1])==0&&distance_self(1,i)1)) j--;
if (i<=j)
{
swap(i,j);
i++;
j--;
}
}
if (il) qs(l,j);
}
void find_1() //找左下角的点
{
root=0;
x[0]=2147483647;
y[0]=2147483647;
for (int i=1;i<=n;i++)
if (x[i]