凸包——求周长、面积

凸包

什么是凸包

在平面图中给定一些点集,去求出一些点:相邻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;
原文地址:https://www.cnblogs.com/HappyKnockOnCode/p/12740087.html