zoukankan      html  css  js  c++  java
  • UVA 12307 Smallest Enclosing Rectangle(旋转卡壳)

    题意:给你一些点,找出两个可以包含所有点的矩形,一个保证矩形面积最小,一个保证矩形周长最小,输出两个最小值

    题解:首先根据所有点求一个凸包,再在这个凸包上枚举每条边,作为矩形的一条边(这样可以保证最小)

       接着根据旋转卡壳的思想求出另外三条边,这样枚举判断就好

       求另三条边时首先方向是确定了的,找点就是旋转卡壳,思想就是:枚举的任意两条边a与b,a的另三条边与b的另三条边都不会再a与b之间,并且b对应边一定最a对应边的        后面(注意是循环的边)那么就是说,我们可以使用类似双指针方式维护,但是时间复杂度却为O(n)

    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<string>
    #include<cstdio>
    #include<cstring>
    #include<iomanip>
    #include<stdlib.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define eps 1E-8
    /*注意可能会有输出-0.000*/
    #define sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型
    #define cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化
    #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0
    #define mul(a,b) (a<<b)
    #define dir(a,b) (a>>b)
    typedef long long ll;
    typedef unsigned long long ull;
    const int Inf=1<<28;
    const ll INF=1LL<<60;
    const double Pi=acos(-1.0);
    const int Mod=1e9+7;
    const int Max=500010;
    struct Point
    {
        double x,y;
        Point(double x=0,double y=0):x(x),y(y) {};
        inline Point operator-(const Point& a)const
        {
            return Point(x-a.x,y-a.y);
        }
        inline bool operator<(const Point& a)const
        {
            return sgn(x-a.x)<0||zero(x-a.x)&&sgn(y-a.y)<0;
        }
            inline Point operator+(const Point& a)const
        {
            return Point(x+a.x,y+a.y);
        }
        inline bool operator!=(const Point& a)const
        {
            return !(zero(x-a.x)&&zero(y-a.y));
        }
    };
    typedef Point Vector;
    struct Line
    {
        Point p;
        Vector v;
        double ang;//极角
        Line() {};
        Line(Point p,Vector v):p(p),v(v)
        {
            ang=atan2(v.y,v.x);
        }
        inline bool operator<(const Line& L)const
        {
            return ang<L.ang;
        }
    };
    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 Cross(Vector A,Vector B)
    {
        return A.x*B.y-A.y*B.x;
    }
    int ConvexHull(Point *p,int n,Point *convex)//求凸包
    {
        sort(p,p+n);
        int m=0;
        for(int i=0; i<n; ++i)
        {
            while(m>1&&Cross(convex[m-1]-convex[m-2],p[i]-convex[m-2])<0)
            {
                m--;
            }
            convex[m++]=p[i];
        }
        int k=m;
        for(int i=n-2; i>=0; --i)
        {
            while(m>1&&Cross(convex[m-1]-convex[m-2],p[i]-convex[m-2])<0)
            {
                m--;
            }
            convex[m++]=p[i];
        }
        if(n>1)
            m--;
        return m;
    }
    Point intersection(Point p1,Point p2,Point l1,Point l2)//交点坐标
    {
        Point ret=p1;//首先计算直线是否平行
        double t=((p1.x-l1.x)*(l1.y-l2.y)-(p1.y-l1.y)*(l1.x-l2.x))
                 /((p1.x-p2.x)*(l1.y-l2.y)-(p1.y-p2.y)*(l1.x-l2.x));
        ret.x+=(p2.x-p1.x)*t;
        ret.y+=(p2.y-p1.y)*t;
        return ret;//线段交点另外判断线段相交(同时判断是否平行)
    }
    Point now[Max],convex[Max];
    double area,per;
    double GetArea(Line up,Line down,Line left,Line right)//根据矩形四条线求面积
    {
        Point minx=intersection(left.p,left.p+left.v,down.p,down.p+down.v);
        Point miny=intersection(right.p,right.p+right.v,down.p,down.p+down.v);
        Point manx=intersection(left.p,left.p+left.v,up.p,up.p+up.v);
        return Dis(minx,manx)*Dis(minx,miny);
    }
    double GetPer(Line up,Line down,Line left,Line right)
    {
        Point minx=intersection(left.p,left.p+left.v,down.p,down.p+down.v);
        Point miny=intersection(right.p,right.p+right.v,down.p,down.p+down.v);
        Point manx=intersection(left.p,left.p+left.v,up.p,up.p+up.v);
        return (Dis(minx,manx)+Dis(minx,miny))*2;
    }
    Vector Rotate(Vector A,double rad) //向量A逆时针旋转rad
    {
    return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
    }
    void RotateStuck(int n)//旋转卡壳枚举矩形
    {
        for(int i=0;i<n;++i)
        {
            convex[i+n]=convex[i];
            convex[i+n+n]=convex[i];
        }
        area=per=Inf;
        Line up,down,left,right;//四条直线
        int i=0,j=0,k=0,l=0;//四条线的位置
        for(; i<n; ++i)//枚举上这条线,则可以确定其他
        {
            up=Line(convex[i],convex[i+1]-convex[i]);//其他三条直线所在的点与上这条线成单峰函数
            k=max(i,k);//每次是逆时针旋转,保证是凸包上一条线或者后面的线
            while(Cross(Rotate(up.v,Pi/2),convex[k+1]-convex[k])<0)//通过旋转来判断
                k++;
                left=Line(convex[k],Rotate(up.v,Pi/2));
            j=max(k,j);
            while(Cross(Rotate(up.v,Pi),convex[j+1]-convex[j])<0)
                j++;
                down=Line(convex[j],Rotate(up.v,Pi));
            l=max(j,l);
            while(Cross(Rotate(up.v,3*Pi/2),convex[l+1]-convex[l])<0)
                l++;
                right=Line(convex[l],Rotate(up.v,3*Pi/2));
            area=min(area,GetArea(up,down,left,right));
            per=min(per,GetPer(up,down,left,right));
        }
        return ;
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n)&&n)
        {
            for(int i=0; i<n; ++i)
            {
                scanf("%lf %lf",&now[i].x,&now[i].y);
            }
            int m= ConvexHull(now,n,convex);
            RotateStuck(m);
            printf("%.2f %.2f
    ",area,per);
        }
        return 0;
    }
  • 相关阅读:
    AVR开发 Arduino方法(六) 内存子系统
    AVR开发 Arduino方法(五) 模数转换子系统
    AVR开发 Arduino方法(四) 串行通信子系统
    AVR开发 Arduino方法(三) 定时/计数器子系统
    AVR开发 Arduino方法(二) 中断子系统
    2014.5.17—所谓生活,就是让自己变得更好
    2014.5.10—做事分清时间地点
    2014.5.7—社交网络用户心理分析
    2014.5.7—20岁这几年
    2014.5.5—反向绑定域名,无需工信部备案
  • 原文地址:https://www.cnblogs.com/zhuanzhuruyi/p/6371875.html
Copyright © 2011-2022 走看看