凸包
什么是凸包
在平面图中给定一些点集,去求出一些点:相邻2点的连线能够将所有的点包围起来

葛立恒(Graham)扫描法
1、先找到左下角的点P0(一定在凸包上)
2、以P0为原点,将其他的点按照极坐标排序,角度小的排在前,若角度相同,距离近的排在前
3、P0 ,P1 入栈,从P2(第三个点)开始,若P2 在直线P0 P1(p[ i-1 ] p [ i ]) 的左边 ,则P2入栈,否则P1 出栈,一直遍历完后面所有点 (这里就需要向量叉乘来判断点在线的左边还是右边)
4、最后留在栈中的点就是凸包上的点

撸代码:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct Point
{
int x,y;
}p[1010];
int XMUL(Point a,Point b,Point c,Point d)/**ab向量 X cd向量*/
{
return ((b.x-a.x)*(d.y-c.y)-(d.x-c.x)*(b.y-a.y));
}
double dis(Point a,Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)*1.0);
}
bool comp(Point a,Point b)
{
int m=XMUL(p[0],a,p[0],b);
if(m>0)
return 1;
else if(m==0&&dis(p[0],a)-dis(p[0],b)<1e-8)
return 1;
return 0;
}
int main()
{
int n,r;
while(~scanf("%d%d",&n,&r))
{
for(int i=0;i<n;i++)
scanf("%d%d",&p[i].x,&p[i].y);
/**找到P0*/
int k=0;
for(int i=1;i<n;i++)
{
if(p[k].y>p[i].y)
k=i;
else if(p[k].y==p[i].y&&p[k].x>p[i].x)
k=i;
}
swap(p[k],p[0]);
/**按照极角坐标排序*/
sort(p+1,p+n,comp);
Point s[1010];
int top=1;
s[0]=p[0];
s[1]=p[1];
for(int i=2;i<n;i++)
{
while(top>=1&&XMUL(s[top-1],s[top],s[top],p[i])<0)
top--;
s[++top]=p[i];
}
double ans=0;
for(int i=0;i<top;i++)
ans+=dis(s[i],s[i+1]);
ans+=dis(s[top],s[0]);
double PI = acos(-1);
ans+=2*PI*r;
printf("%.0f
",ans);
}
return 0;
}
若要求凸包的面积
还是先求出凸包上的点,再根据三角形面积公式(叉乘计算)
/**求凸包面积,{1/2*a*b*sin(c)} ==a,b两向量叉乘 */
int area=0;
for(int i=1;i<top;i++)
{
area+=cross(s[0],s[i],s[i+1]);
}
area=abs(area)/2;