写篇博客证明窝没有在期末考中AFO
由于笔者太菜,所以只会Andrew算法
Andrew算法
Andrew算法是Graham扫描法的变种,Andrew更快,更稳定
先把所有的点按照x从小到大(x相等时,y也按从小到大)排序
删除重复点(依据题目而确定是否要这个步骤)
画几个图,会发现第一个点和最后一个点都一定在凸包中
我们先从前向后扫描,维护下凸壳
再从后向前扫描,维护上凸壳
这样就能求出凸包,复杂度为(O(N log N))
#include <bits/stdc++.h>
#define db double
#define vec Point
#define N 10005
using namespace std;
struct Point{
db x,y;
Point(db x=0,db y=0):x(x),y(y) {}
};
vec operator - (Point a,Point b){
return vec(a.x-b.x,a.y-b.y);
}
bool operator < (const Point& a,const Point& b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
Point p[N],ch[N];
inline db cross(register vec a,register vec b)
{
return a.x*b.y-a.y*b.x;
}
inline db dis(register Point a,register Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
int n;
scanf("%d",&n);
for(register int i=1;i<=n;++i)
scanf("%lf%lf",&p[i].x,&p[i].y);
sort(p+1,p+1+n);
int m=1;
for(register int i=1;i<=n;++i)
{
while(m>2&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
--m;
ch[m++]=p[i];
}
int k=m;
for(register int i=n-1;i;--i)
{
while(m>k&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)
--m;
ch[m++]=p[i];
}
db ans=0;
for(register int i=1;i<m-1;++i)
ans+=dis(ch[i],ch[i+1]);
printf("%.2lf",ans);
return 0;
}