首页 > 其他 > 详细

「凸包」学习笔记

时间:2020-02-01 22:07:32      阅读:93      评论:0      收藏:0      [点我收藏+]
  • 前言

    凸包真难。

    代码如果相似是因为我就是向别人学的。

    (为什么没人讲向量..第一次学不懂向量然后代码硬是看不懂嘤嘤嘤..)


  • 向量及运算的芝士(可能摘自很多地方..

    定义:有大小方向的量,又称为矢量

    坐标\(A(x_1,y_1),B(x_2,y_2)\)

    向量\(\overrightarrow{AB}=(x_2-x_1,y_2-y_1)\)

    加法:\((x_1+x_2,y_1+y_2)\)

    减法:\((x_1-x_2,y_1-y_2)\)

    点积:\(a·b=x_1x_2+y_1y_2\)

    1. \(a·b=0\)\(a \perp b\)
    2. \(a·b<0\) 则他们的夹角大于90
    3. \(a·b>0\) 则他们的夹角小于90

    叉积:\(a×b=x_1y_2-x_2y_1\)

    1. \(a×b=0\)\(a\)\(b\)共线(可以反向)
    2. \(a×b>0\)\(b\)\(a\)逆时针方向
    3. \(a×b<0\)\(b\)\(a\)顺时针方向

  • 有啥用?求什么

    给出一堆点,再用一根绳子包住,这就是个凸包啦。

    然后一般问绳子的长度。


  • 如何实现?

    主要分为2部:求上半部分和下半部分。

    首先,先对每一个点以\(x\)坐标从小到大排序,如果一样再以\(y\)坐标从小到大排序。

    比如上面那个例子:

    技术分享图片

    初始化\((1)(2)\)放入栈中,此时栈中有\((1)(2)\)

    然后把\((3)\)放入栈中,此时栈中有\((1)(2)\)

    因为此时在求下半部分,因此\((3)\)我们希望越下越好,即\(\overrightarrow{(1)(2)}×\overrightarrow{(2)(3)} \geqslant0\),(叉积的定义),然后可以发现\((3)\)满足的:

    技术分享图片

    所以栈不改变,栈中有\((1)(2)(3)\)

    然后,把\((4)\)放入栈中,\((4)\)满足\(\overrightarrow{(2)(3)}×\overrightarrow{(3)(4)} \geqslant0\),所以栈不改变:\((1)(2)(3)(4)\)

    技术分享图片

    然后把\((5)\)放入栈中,发现\((5)\)不满足\(\overrightarrow{(3)(4)}×\overrightarrow{(4)(5)} \geqslant0\),所以把\((4)\)弹出栈

    而出栈后发现,\((5)\)不满足\(\overrightarrow{(2)(3)}×\overrightarrow{(3)(5)} \geqslant0\),所以把\((3)\)踢出栈。此时栈中剩下:\((1)(2)(5)\)

    技术分享图片

    \((6)\)放入栈,\((6)\)满足\(\overrightarrow{(2)(5)}×\overrightarrow{(5)(6)} \geqslant0\),不改变栈:\((1)(2)(5)(6)\)

    技术分享图片

    \((7)\)放入栈,\((7)\)满足\(\overrightarrow{(5)(6)}×\overrightarrow{(6)(7)} \geqslant0\),不改变栈:\((1)(2)(5)(6)(7)\)

    注:可能画歪了..\((6)(7)\)\(y\)坐标相同

    技术分享图片

    \((8)\)放入栈,\((8)\)不满足\(\overrightarrow{(6)(7)}×\overrightarrow{(7)(8)} \geqslant0\),所以把\((7)\)踢出\((1)(2)(5)(6)(8)\)

    但是发现,此时仍不满足\(\overrightarrow{(5)(6)}×\overrightarrow{(6)(8)} \geqslant0\),所以再把\((6)\)踢出,栈中剩下:\((1)(2)(5)(8)\)

    技术分享图片

    这样,下部分的凸包就完成啦,而上部分反着做一遍就好了。


  • 代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
struct point{
    double x,y;
}p[100010];
int n,sta[100010],cnt;
double ans;
point getvec(point a,point b){return point{(b.x-a.x),(b.y-a.y)};}
double dis(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
double xmul(point a,point b){return a.x*b.y-a.y*b.x;}
bool cmp(point a,point b)
{   
        if(a.x==b.x)return a.y<b.y;
        return a.x<b.x;
}
int main()
{   
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
        sort(p+1,p+1+n,cmp);
        sta[++cnt]=1;sta[++cnt]=2;
        for(int i=3;i<=n;i++)
        {   
            point u=getvec(p[sta[cnt-1]],p[sta[cnt]]);
            point v=getvec(p[sta[cnt]],p[i]);
            while(xmul(u,v)<0.0)
            {   
                if(cnt==1)break;
                cnt--;
                u=getvec(p[sta[cnt-1]],p[sta[cnt]]);
                v=getvec(p[sta[cnt]],p[i]);
            }
            sta[++cnt]=i;
        }
        int tmp=cnt;
        sta[++cnt]=n;sta[++cnt]=n-1;
        for(int i=n-2;i>=1;i--)
        {   
            point u=getvec(p[sta[cnt-1]],p[sta[cnt]]);
            point v=getvec(p[sta[cnt]],p[i]);
            while(xmul(u,v)<0.0)
            {   
                if(cnt==tmp+1)break;
                cnt--;
                u=getvec(p[sta[cnt-1]],p[sta[cnt]]);
                v=getvec(p[sta[cnt]],p[i]);
            }
            sta[++cnt]=i;
        }
        for(int i=1;i<=cnt-1;i++)
            ans+=dis(p[sta[i]],p[sta[i+1]]);
        printf("%.2lf\n",ans); 
        return 0;
}

「凸包」学习笔记

原文:https://www.cnblogs.com/Rainy7/p/12250381.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!