凸包入门

什么是凸包?

假设平面上有p0~p12共13个点,过某些点作一个多边形,使这个多边形能把所有点都“包”起来。当这个多边形是凸多边形的时候,我们就叫它“凸包”。如下图: 
凸包入门

然后,什么是凸包问题? 
我们把这些点放在二维坐标系里面,那么每个点都能用 (x,y) 来表示。 
现给出点的数目13,和各个点的坐标。求构成凸包的点?

自己才刚刚接触到这个数学问题。通过几个入门的简单的题,基本上已经有了简单的了解。所以自己先写点东西。为了自己以后

可以好好的复习。

其实凸包就是凸多边形问题。

大佬的博客:凸包五解

                    点击打开链接

   1 凸包问题要求什么?

一般的话来说,入门就是要你找出这个凸多边型,求凸多边的型的面积,周长。其实写到这就可以思考一下,如何求多边。只要

把多边形求出来,那么相对来说就是可以找到周长,面积了。

  2: 如何求?
其实大佬的博客中,将这个思想已经完全的讲解出来了。

(1)点的输入

(2)找出很明显的凸包上点的,作为一个开头。

(3)极角排序。

int dis(node c1,node c2)
{
    return (c1.x-c2.x)*(c1.x-c2.x)+(c1.y-c2.y)*(c1.y-c2.y);
}
double mutil(node c0,node c1,node c2)
{
    return (c1.x-c0.x)*(c2.y-c0.y)-(c2.x-c0.x)*(c1.y-c0.y);
}
int cmp(node c1,node c2)
{
    int x=mutil(c1,c2,a[0]);
    if(x>0||(x==0&&dis(c1,a[0])<dis(c2,a[0])))
        return 1;
    else
        return 0;
}


(4)开始扫描,利用叉乘来判断是不是凸包上的点,将凸包上的点收入到栈堆中(数组也可以)

void Graham()
{
    tot=2;
    p[0]=a[0],p[1]=a[1];
    for(int i=2; i<n; i++)
    {
        while(tot>1&&mutil(p[tot-1],p[tot-2],a[i])>=0)
            tot--;
        p[tot++]=a[i];
    }
}

俩个简单的题

 NYOJ-78 圈水池 入门凸包输出点

int n,tot;
struct node
{
    int x,y;
} a[10005],p[10005];
int dis(node c1,node c2)
{
    return (c1.x-c2.x)*(c1.x-c2.x)+(c1.y-c2.y)*(c1.y-c2.y);
}
double mutil(node c0,node c1,node c2)
{
    return (c1.x-c0.x)*(c2.y-c0.y)-(c2.x-c0.x)*(c1.y-c0.y);
}
int cmp(node c1,node c2)
{
    int x=mutil(c1,c2,a[0]);
    if(x>0||(x==0&&dis(c1,a[0])<dis(c2,a[0])))
        return 1;
    else
        return 0;
}
int cmp1(node a,node b)
{
    if(a.x==b.x)
        return a.y<b.y;
    else
        return a.x<b.x;
}
void Graham()
{
    tot=2;
    p[0]=a[0],p[1]=a[1];
    for(int i=2; i<n; i++)
    {
        while(tot>1&&mutil(p[tot-1],p[tot-2],a[i])>=0)
            tot--;
        p[tot++]=a[i];
    }
    sort(p,p+tot,cmp1);
    for(int i=0;i<tot;i++)
        printf("%d %d\n",p[i].x,p[i].y);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {


        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        int k=0;
        for(int i=0; i<n; i++)
        {
            if(a[i].y<a[k].y||(a[i].y==a[k].y&&a[i].x<a[k].x))
                k=i;
        }
        swap(a[0],a[k]);
        sort(a+1,a+n,cmp);
//        for(int i=0; i<n; i++)
//        {
//            printf("******%d %d\n",a[i].x,a[i].y);
//        }
        Graham();


    }
}

 POJ-3348 Cows 入门求面积

 void Graham()
    {
        tot=2;
        p[0]=a[0],p[1]=a[1];
        for(int i=2; i<n; i++)
        {
            while(tot>1&&mutil(p[tot-1],p[tot-2],a[i])>=0)
                tot--;
            p[tot++]=a[i];
        }
        int sum=0;
        for(int i=2; i<tot; i++)
        {
            int l=(int)mutil(p[0],p[i-1],p[i]);                   //在求面积的时候就可以直接用向量来求。即平行四边的面积


            就等于两条边的乘积除以2;
            sum+=abs(l)/2;
        }
        printf("%d",sum/50);
    }