zoukankan      html  css  js  c++  java
  • 二维凸包模板(凸包重心,周长,面积,直径,最大三角形,最小环绕矩形)

    #include"string.h"
    #include"stdio.h"
    #include"iostream"
    #include"algorithm"
    #include"queue"
    #include"stack"
    #define M 100009
    #define N 100009
    #include"stdlib.h"
    #include"math.h"
    #define inf 10000000000000000LL
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    #define eps 1e-10
    using namespace std;
    struct node
    {
        double x,y;
        node(){}
        node(double _x,double _y):x(_x),y(_y){}
        node operator +(node p)//向量加法
        {
            return node(x+p.x,y+p.y);
        }
        node operator -(node p)//向量减法
        {
            return node(x-p.x,y-p.y);
        }
        double operator *(node p)//向量叉乘
        {
            return x*p.y-y*p.x;
        }
        double operator ^(node p)//向量点乘
        {
            return x*p.x+y*p.y;
        }
        node operator /(double p)//向量除法
        {
            return node(x/p,y/p);
        }
        node operator *(double p)//向量乘法
        {
            return node(x*p,y*p);
        }
    }p[M],q[M];
    int cnt,n;
    double max(double x,double y)
    {
        return x>y?x:y;
    }
    double min(double x,double y)
    {
        return x<y?x:y;
    }
    double cross(node a,node b,node c)//叉积
    {
        return (b-a)*(c-a);
    }
    double dot(node a,node b,node c)//点积
    {
        return (b-a)^(c-a);
    }
    double len(node a)//向量长吨
    {
        return sqrt(a^a);
    }
    double dis(node a,node b)//两点距离
    {
        return len(b-a);
    }
    int cmp(node a,node b)//极角排序
    {
        double temp=cross(p[0],a,b);//逆时针排序
        if(temp>0)
            return 1;
        else if(fabs(temp)<eps&&dis(p[0],a)<dis(p[0],b))//角度相同则按照距离排序
            return 1;
        else
            return 0;
    }
    void input(int n)//输入
    {
        for(int i=0;i<n;i++)
            scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    void sort_point(int n)//凸包点集的输入即排序
    {
        int i,k;
        node start;
        start=p[0];
        k=0;
        for(i=1;i<n;i++)
        {
            if((start.y>p[i].y)||(fabs(start.y-p[i].y)<eps&&start.x>p[i].x))
            {
                start=p[i];
                k=i;
            }
        }
        p[k]=p[0];
        p[0]=start;
        sort(p+1,p+n,cmp);
    }
    void be_weight(int val)
    {
        int temp=val;
        n=1;
        for(int i=1;i<temp;i++)
        {
            if(fabs(p[i-1].x-p[i].x)<eps&&fabs(p[i-1].y-p[i].y)<eps)
                continue;
            p[n++]=p[i];
        }
    }
    void Convex_hull(int n)//求凸包凸包上的点存在q中
    {
        int i;
        if(n==1)
        {
            q[0]=p[0];
            cnt=1;
        }
        else if(n==2)
        {
            q[0]=p[0];
            q[1]=p[1];
            q[2]=p[0];
            cnt=2;
        }
        else if(n>=3)
        {
            q[0]=p[n-1];
            q[1]=p[0];
            q[2]=p[1];
            cnt=2;
            for(i=2;i<n;i++)
            {
                while(cross(q[cnt-1],q[cnt],p[i])<0)
                    cnt--;
                q[++cnt]=p[i];
            }
        }
    }
    double Perimeter(int cnt)//凸包周长
    {
        double sum=0;
        for(int i=1;i<=cnt;i++)
            sum+=dis(q[i-1],q[i]);
        return sum;
    }
    double Area(int cnt)//凸包面积
    {
        double sum=0;
        node p(0,0);
        for(int i=1;i<=cnt;i++)
            sum+=cross(p,q[i-1],q[i]);
        return fabs(sum/2.0);
    }
    node barycenter_cur(int n)//原多边形的重心
    {
        double sum=0;
        node ret(0.0,0.0);
        for(int i=2;i<n;i++)
        {
            double area=cross(p[0],p[i-1],p[i]);
            sum+=area;
            ret=ret+(p[0]+p[i-1]+p[i])/3.0*area;
        }
        ret=ret/sum;
        return ret;
    }
    node barycenter_now(int cnt)//凸包的重心
    {
        double sum=0;
        node ret(0.0,0.0);
        for(int i=2;i<cnt;i++)
        {
            double area=cross(q[0],q[i-1],q[i]);
            sum+=area;
            ret=ret+(q[0]+q[i-1]+q[i])/3.0*area;
        }
        ret=ret/sum;
        return ret;
    }
    double Diameter(int cnt)//旋转卡壳法求凸包的直径即最大的点对距离
    {
        double maxi=0;
        int j=1;
        for(int i=1;i<=cnt;i++)
        {
            while(fabs(cross(q[i-1],q[i],q[(j+1)%cnt]))>fabs(cross(q[i-1],q[i],q[j%cnt])))
                j++;
            maxi=max(maxi,dis(q[i-1],q[j%cnt]));
            maxi=max(maxi,dis(q[i],q[j%cnt]));
        }
        return maxi;
    }
    double Max_triangle(int cnt)//旋转卡壳法求面积最大的三角形
    {
        double maxi=0;
        int j=1;
        int k=1;
        for(int i=1;i<=cnt;i++)
        {
            while(fabs(cross(q[i-1],q[j%cnt],q[(k+1)%cnt]))>fabs(cross(q[i-1],q[j%cnt],q[k%cnt])))
                k++;
            maxi=max(maxi,fabs(cross(q[i-1],q[j%cnt],q[k%cnt])));
            while(fabs(cross(q[i-1],q[(j+1)%cnt],q[k%cnt]))>fabs(cross(q[i-1],q[j%cnt],q[k%cnt])))
                j++;
            maxi=max(maxi,fabs(cross(q[i-1],q[j%cnt],q[k%cnt])));
        }
        return maxi/2.0;
        /*其思路是这样的,定点I,p,q,先I,p固定,让q旋转找到最大的面积三角形,之后,I,q固定,p旋转,
            找到最大的三角形面积,比较记录.然后i++;直到i遍历所有顶点.所求出来的三角形就是面积
            最大.这里的旋转卡壳思想就是固定,旋转.这样的.显然i++后,p,q两点不需要再从i+1,i+2开始,这
            个好形容,对p,q进行取模运算的时候,注意自己的SP栈指针多大.*/
    }
    void Min_rectangle(int cnt)//旋转卡壳法求面积和周长最小的环绕矩形
    {
        if(cnt<=2)//输出时注意的地方*****
        {
            if(cnt==1)
                printf("%.2lf %.2lf
    ",0.0,0.0);
            else
                printf("%.2lf %.2lf
    ",0.0,2*dis(p[0],p[1]));
            return;
        }
        double S=inf,C=inf;
        int j,k,r;
        double h,w;
        j=k=r=1;
        for(int i=1;i<=cnt;i++)
        {
            double L=dis(q[i-1],q[i]);
            while(fabs(cross(q[i-1],q[i],q[(j+1)%cnt]))>fabs(cross(q[i-1],q[i],q[j%cnt])))
                j++;
            h=fabs(cross(q[i-1],q[i],q[j%cnt]))/L;
            while(dot(q[i-1],q[i],q[(k+1)%cnt])>dot(q[i-1],q[i],q[k%cnt]))
                k++;
            if(i==1)
                r=k;
            while(dot(q[i-1],q[i],q[(r+1)%cnt])<=dot(q[i-1],q[i],q[r%cnt]))
                r++;
            w=(dot(q[i-1],q[i],q[k%cnt])-dot(q[i-1],q[i],q[r%cnt]))/L;
            S=min(S,w*h);
            C=min(C,(w+h)*2);
        }
        printf("%.2lf ",S);//输出时注意的地方*****
        printf("%.2lf
    ",C);
    }
    int main()
    {
        while(scanf("%d",&n),n)
        {
            input(n);//输入
            sort_point(n);//极角排序
            be_weight(n);//去重
            Convex_hull(n);//求凸包
            Min_rectangle(cnt);
        }
        return 0;
    }
    

  • 相关阅读:
    自定义事件 Event 、CustomEvent的使用
    移动端适配方案总结
    @media screen媒体查询实现页面自适应布局
    判断页面所有图片加载完成后执行操作
    JQ选择器篇2
    JQ 选择器篇1
    sql 日期转换字符大法
    SQL server从入门精通----3种分页
    SQL server从入门精通----触发器
    SQL server从入门精通---- 事务
  • 原文地址:https://www.cnblogs.com/mypsq/p/4348133.html
Copyright © 2011-2022 走看看