• 凸包学习笔记


      凸包指给出N个点,选择尽量少的点连线,将所有的点全部包含在所连成的凸多边形内。

      首先,对于两个点P,Q,若原点为O,可使用叉积$overrightarrow{OP}*overrightarrow{OQ}$计算出P与Q相对于O点的方向,若叉积小于0则P在Q的逆时针方向。

      对于一个点集,首先搜索出纵坐标最小的点P。假设P不在凸包上,没有两个点连线能够在P点下方,因此P点一定在凸包上。然后,将所有点,以P点为中心,进行排序。与P点夹角最小的点在前,若遇到两点与P共线,则距离小的点在前。

      然后,先将第一和第二个点放入栈s,从第三个点开始计算,更新到第i个点时栈s内的元素表示0-i元素凸包上的点。随后执行以下操作:

    1. 对第i个点,若该点与栈顶点组成的向量,在与栈第二个点形成向量的顺时针方向,即二者叉积大于0,则代表栈顶元素不是凸包的点,将栈顶元素弹出,反复执行该操做。
    2. 随后将第i个点加入栈内。
    3. 对第i+1个点执行操作。

      最后得到的栈内的元素即为凸包的边,按逆时针方向排序。

      但是,这种做法会遇到一种问题,就是N个点共线。只需要对排序后的点集地0,1,N-1这3个点是否共线,如果共线则输出第0与N-1个点的距离即可。

      最经典例题是HDU1392与洛谷2742

      http://acm.hdu.edu.cn/showproblem.php?pid=1392

      https://www.luogu.org/problem/P2742

      最后附上打了一下午的HDU1392代码,当时对1个点,2个点,以及共线点没有判断卡了很久。

      

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <int ,int> pii;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define de(x) cout<< #x<<" = "<<x<<endl
    #define dd(x) cout<< #x<<" = "<<x<<" "
    #define mes(a,b) memset(a,b,sizeof a)
    const int inf= 0x3f3f3f3f;
    const int maxn=105;
    
    pii point[maxn];//存放点,下标从0开始 
    double dis(const pii &s1,const pii &s2)
    {
        return sqrt((s1.fi-s2.fi)*(s1.fi-s2.fi)+(s1.se-s2.se)*(s1.se-s2.se));
    }
    pii operator -(const pii &s1,const pii &s2)
    {
        return mp(s1.fi-s2.fi,s1.se-s2.se);
    }
    int s[maxn];//
    int chaji(const pii &s1,const pii &s2)//差积 
    {
        return s1.fi*s2.se-s1.se*s2.fi;
    }
    bool comp(const pii &s1,const pii &s2)
    {
        int x=chaji(s1-point[0],s2-point[0]);
        if( x>0|| (x==0&&fabs(s1.fi-point[0].fi)<fabs(s2.fi-point[0].fi)) ) return 1;
        else return 0;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cout.tie(0);
        cin.tie(0);
        while(true)
        {
            int n,cnt=0;//n为点个数,cnt为凸包点个数 
            cin>>n;
            if(!n) break;
            rep(i,0,n) cin>>point[i].fi>>point[i].se;
            if(n==1)
            {
                cout<<"0.00"<<"
    ";
                return 0; 
            }
            else if(n==2)
            {
                cout<<fixed<<setprecision(2)<<dis(point[0],point[1])<<"
    ";
                continue;
            }
            int p=0;
            //将下边界的点放到第一位 
            rep(i,1,n)
                if( point[i].se<point[p].se||(point[i].se==point[p].se&&point[i].fi<point[p].fi) )
                    p=i;
            swap(point[0],point[p]);
            sort(point+1,point+n,comp);
            
            //所有点共线 
            if(chaji(point[n-1]-point[0],point[1]-point[0])==0)
            {
                cout<<fixed<<setprecision(2)<<dis(point[n-1],point[0])<<endl;
                continue;
            }
            //将第0个和第1个点加入栈 
            s[cnt++]=0;
            s[cnt++]=1;
            rep(i,2,n)
            {
                while(chaji( point[s[cnt-1]]-point[i],point[s[cnt-2]]-point[i] )>=0 ) cnt--;//将非凸包的点弹出 
                s[cnt++]=i;
            }
            //凸包计算完成,从0到cnt-1存在s中 
            double ans=0;//ans为多边形长度 
            rep(i,0,cnt) ans+=dis(point[s[i]] , point[s[(i+1)%cnt]] );
            cout<<fixed<<setprecision(2)<<ans<<"
    ";
        }
        return 0;
    }
  • 相关阅读:
    UART和RS232/RS485的关系是什么?
    Async & Await 的前世今生
    asp.net EFcore配置链接sqlserver
    ASP.NET Core启动流程
    ASP.NET Core 过滤器
    Nginx简介及配置文件详解
    3.ASP.NET Core Docker学习-构建单机多容器环境
    2.ASP.NET Core Docker学习-镜像容器与仓库
    asp.net core 依赖注入
    1.ASP.NET Core Docker学习-Docker介绍与目录
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/11514201.html
Copyright © 2020-2023  润新知