主要思想
先将所给点以x坐标从小到大(若x相等,以y从小到大)排序,从第一个点开始从左到右扫一遍,用叉积维护下凸壳(上凸壳亦可),在从右到左扫一遍,维护上(下)凸壳即可。
代码如下:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,zz;
struct dian
{int x,y;} d[100002],tb[100010];
bool kp(const dian &a,const dian &b)
{
if(a.x<b.x) return true;
else if(a.x==b.x&&a.y<b.y) return true;
else return false;
}
int xj(dian &a,dian &b,dian &c)//叉积
{
int x1=a.x-c.x, y1=a.y-c.y,
x2=b.x-c.x, y2=b.y-c.y;
return x1*y2-x2*y1;
}
void tubao()//凸包andrew算法
{
zz=0;
for(int i=1;i<=n;i++)
{while(zz>=2&&xj(tb[zz-1],d[i],tb[zz-2])<0) zz--;
tb[zz].x=d[i].x; tb[zz].y=d[i].y; zz++;
}
int k=zz;
for(int i=n-1;i>=1;i--)
{while(zz>k&&xj(tb[zz-1],d[i],tb[zz-2])<0) zz--;
tb[zz].x=d[i].x; tb[zz].y=d[i].y; zz++;
}
if(n>1)zz-=2;//x坐标最小的点会被计算两次且zz比点数大1。
else if(n==1) zz--;
for(int i=0;i<=zz;i++) printf("%d %d\n",tb[i].x,tb[i].y);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&d[i].x,&d[i].y);
sort(d+1,d+n+1,kp);//预处理
tubao();
return 0;
}