Graham算法
先找出以(y)值为第一关键字和以(x)值为第二关键字最小的点,以其作为基准点
然后对剩下的点进行极角序排序
向栈中加点,并维护凸性,最终栈中的点即为凸包上的点
复杂度即为排序的复杂度(O(n log n))
(code:)
struct point
{
double x,y;
}p[maxn],st[maxn];
point operator -(const point &a,const point &b)
{
return (point){a.x-b.x,a.y-b.y};
}
double operator *(const point &a,const point &b)
{
return a.x*b.y-a.y*b.x;
}
double dis(const point &a,const point &b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool cmp1(const point &a,const point &b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmp2(const point &a,const point &b)
{
if((a-p[1])*(b-p[1])==0) return dis(a,p[1])<dis(b,p[1]);
return (b-a)*(p[1]-a)>0;
}
void graham()
{
sort(p+1,p+n+1,cmp1);
sort(p+2,p+n+1,cmp2);
st[1]=p[1],top=1;
for(int i=2;i<=n;++i)
{
while(top>1&&(st[top-1]-p[i])*(st[top]-p[i])<=0) top--;
st[++top]=p[i];
}
}
旋转卡壳
对踵点,如果过凸多边形上两点作一对平行线,使得整个多边形都在这两条线之间,那么这两个点被称为一对对踵点,直径一定会在对踵点中产生
逆时针枚举边,然后从上次枚举到对踵点的继续逆时针向后枚举来求解
实现时用双指针法来保证(O(n))的复杂度,用叉积求面积来判断点到边的距离
(code:)
struct point
{
int x,y;
}p[maxn],st[maxn];
point operator -(const point &a,const point &b)
{
return (point){a.x-b.x,a.y-b.y};
}
double operator *(const point &a,const point &b)
{
return a.x*b.y-a.y*b.x;
}
int dis(const point &a,const point &b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp1(const point &a,const point &b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmp2(const point &a,const point &b)
{
if((a-p[1])*(b-p[1])==0) return dis(a,p[1])<dis(b,p[1]);
return (b-a)*(p[1]-a)>0;
}
void graham()
{
sort(p+1,p+n+1,cmp1);
sort(p+2,p+n+1,cmp2);
st[1]=p[1],top=1;
for(int i=2;i<=n;++i)
{
while(top>1&&(st[top-1]-p[i])*(st[top]-p[i])<=0) top--;
st[++top]=p[i];
}
}
void get()
{
int j=1;
st[top+1]=st[1];
for(int i=1;i<=top;++i)
{
while((st[i+1]-st[i])*(st[j]-st[i])<(st[i+1]-st[i])*(st[j+1]-st[i])) j=(j+1)%top;
ans=max(ans,max(dis(st[i],st[j]),dis(st[i+1],st[j])));
}
}