zoukankan      html  css  js  c++  java
  • 1185: [HNOI2007]最小矩形覆盖

    题目描述

    给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,
    输出所求矩形的面积和四个顶点坐标
     

    输入

    第一行为一个整数n(3<=n<=50000)
    从第2至第n+1行每行有两个浮点数,表示一个顶点的x和y坐标,不用科学计数法
     

    输出

    第一行为一个浮点数,表示所求矩形的面积(精确到小数点后5位),
    接下来4行每行表示一个顶点坐标,要求第一行为y坐标最小的顶点,
    其后按逆时针输出顶点坐标.如果用相同y坐标,先输出最小x坐标的顶点

    样例输入

    6 1.0 3.00000
    1 4.00000
    2.0000 1
    3 0.0000
    3.00000 6
    6.0 3.0

    样例输出

    18.00000
    3.00000 0.00000
    6.00000 3.00000
    3.00000 6.00000
    0.00000 3.00000
     
     
     
     
    暴力过的,先把坐标旋转,计算新坐标系下所有点的新的坐标,找到4个角,然后把4个角的坐标转成原坐标系下的坐标,时间复杂度O(n^2),涉及角度转换,时间常数也很大
    #include<iostream>
    #include<stdio.h>
    #include<math.h>
    #include<algorithm>
    using namespace std;
    
    typedef struct {
        double x,y;
    }Point;
    Point p[50005];
    int n;
    int Q[50005],top;
    int ans[50005];
    
    bool cmp(Point a,Point b){
        return a.y<b.y||(a.y==b.y&&a.x<b.x);
    }
    
    double cross(int i,int j,int k){
        Point a=p[i];
        Point b=p[j];
        Point c=p[k];
        return (c.x-b.x)*(a.y-b.y)-(c.y-b.y)*(a.x-b.x);
    
    }
    
    void scan(){
        sort(p+1,p+1+n,cmp);
        
        Q[1]=1;Q[2]=2;top=2;
        
        for(int i=3;i<=n;++i)
        {
            while(top>1&&cross(Q[top-1],Q[top],i)<=0) top--;
            Q[++top]=i;
        }
        
        ans[0]=top;
        for(int i=1;i<=top;++i)
        ans[i]=Q[i];
        
        Q[1]=n;Q[2]=n-1;top=2;
        for(int i=n-2;i>=1;--i)
        {
            while(top>1&&cross(Q[top-1],Q[top],i)<=0) top--;
            Q[++top]=i;
        }
        
        for(int i=2;i<top;++i)
        {
            ans[0]++;
            ans[ans[0]]=Q[i];
        }
    
    }
    
    double computeTheta(int i,int j){
        Point a=p[i];
        Point b=p[j];
        if(a.y>b.y) {Point c=a;a=b;b=c;}
    //    cout<<(b.x-a.x)<<" "<<sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))<<"  "<<(b.x-a.x)/sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))<<"  "<<acos((b.x-a.x)/sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y)))<<endl;
        return acos((b.x-a.x)/sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))); 
    }
    bool isBetter(Point tempPoint[],Point ansPoint[]){
        for(int i=0;i<3;++i)
        {
            if(tempPoint[i].y<ansPoint[i].y||(tempPoint[i].y==ansPoint[i].y&&tempPoint[i].x<ansPoint[i].x)) return true;
            if(tempPoint[i].y>ansPoint[i].y||(tempPoint[i].y==ansPoint[i].y&&tempPoint[i].x>ansPoint[i].x)) return false;
        }
        
        return false;
    
    }
    int main()
    {
        scanf("%d",&n);
        
        for(int i=1;i<=n;++i)
        scanf("%lf %lf",&p[i].x,&p[i].y);
    
        scan(); 
        
        ans[0]++;
        ans[ans[0]]=1;
        
        double x,y; 
        double minarea;
        bool initialArea=true;
        double minx,maxx,miny,maxy;
        bool initialXY=true;
        Point ansPoint[4];
        
        for(int i=1;i<ans[0];++i)
        {
        //    cout<<p[ans[i]].x<<" "<<p[ans[i]].y<<" "<<p[ans[i+1]].x<<" "<<p[ans[i+1]].y<<endl;
            double theta=computeTheta(ans[i],ans[i+1]);
            initialXY=true;
            for(int j=1;j<ans[0];++j)
            {
                x=p[ans[j]].x*cos(theta)+p[ans[j]].y*sin(theta);
                y=p[ans[j]].y*cos(theta)-p[ans[j]].x*sin(theta);
                if(initialXY==true)
                {
                    minx=x;maxx=x;miny=y;maxy=y;
                    initialXY=false;
                }
                if(initialArea==false&&(maxx-minx)*(maxy-miny)>minarea+0.5) break;
                if(x<minx) minx=x;
                if(x>maxx) maxx=x;
                if(y<miny) miny=y;
                if(y>maxy) maxy=y;
            }
            
        //    cout<<theta<<"  "<<(maxx-minx)*(maxy-miny)<<"  fdg"<<endl;
            
            if(initialArea==true||(maxx-minx)*(maxy-miny)<minarea)
            {
                initialArea=false;
                minarea=(maxx-minx)*(maxy-miny);
                ansPoint[0].x=minx*cos(theta)-miny*sin(theta);
                ansPoint[0].y=minx*sin(theta)+miny*cos(theta);
                
                ansPoint[1].x=minx*cos(theta)-maxy*sin(theta);
                ansPoint[1].y=minx*sin(theta)+maxy*cos(theta);
                
                ansPoint[2].x=maxx*cos(theta)-miny*sin(theta);
                ansPoint[2].y=maxx*sin(theta)+miny*cos(theta);
                
                ansPoint[3].x=maxx*cos(theta)-maxy*sin(theta);
                ansPoint[3].y=maxx*sin(theta)+maxy*cos(theta);
            }
            else if(initialArea==false&&fabs((maxx-minx)*(maxy-miny)-minarea)<1e-6)
            {
            //    cout<<"NOW  "<<(maxx-minx)*(maxy-miny)<<endl;
                Point tempPoint[4];
                tempPoint[0].x=minx*cos(theta)-miny*sin(theta);
                tempPoint[0].y=minx*sin(theta)+miny*cos(theta);
                
                tempPoint[1].x=minx*cos(theta)-maxy*sin(theta);
                tempPoint[1].y=minx*sin(theta)+maxy*cos(theta);
                
                tempPoint[2].x=maxx*cos(theta)-miny*sin(theta);
                tempPoint[2].y=maxx*sin(theta)+miny*cos(theta);
                
                tempPoint[3].x=maxx*cos(theta)-maxy*sin(theta);
                tempPoint[3].y=maxx*sin(theta)+maxy*cos(theta);
                
                sort(ansPoint,ansPoint+4,cmp);
                sort(tempPoint,tempPoint+4,cmp);
                if(isBetter(tempPoint,ansPoint))
                {
                    ansPoint[0]=tempPoint[0];
                    ansPoint[1]=tempPoint[1];
                    ansPoint[2]=tempPoint[2];
                    ansPoint[3]=tempPoint[3];
                }
                
                
            
            }
            
        }
        
        printf("%.5f
    ",minarea);
        for(int i=0;i<=3;++i)
        {
            if(fabs(ansPoint[i].x)<1e-6)
            ansPoint[i].x=0;
            if(fabs(ansPoint[i].y)<1e-6)
            ansPoint[i].y=0;
        }
        
        n=4;
        for(int i=1;i<=4;++i)
        p[i]=ansPoint[i-1];
        scan();
        
        for(int i=1;i<=4;++i)
        printf("%.5f %.5f
    ",p[ans[i]].x,p[ans[i]].y);
    
        return 0;
    
    } 

    看到其他人的题解,挺好的,旋转卡壳,时间复杂度O(N),下面这个代码很优雅,侵删

    #include<bits/stdc++.h>
    #define db double
    using namespace std;
    const int M=5e4+5;
    const db eps=1e-8;
    struct pt{db x,y;};
    int sig(db x){return (x>eps)-(x<-eps);}
    pt operator -(pt a,pt b){return (pt){a.x-b.x,a.y-b.y};}
    pt operator +(pt a,pt b){return (pt){a.x+b.x,a.y+b.y};}
    db operator *(pt a,pt b){return a.x*b.y-a.y*b.x;}
    db operator /(pt a,pt b){return a.x*b.x+a.y*b.y;}
    pt operator *(pt a,db b){return (pt){a.x*b,a.y*b};}
    pt operator /(pt a,db b){return (pt){a.x/b,a.y/b};}
    bool operator <(pt a,pt b){return !sig(a.y-b.y)?a.x<b.x:a.y<b.y;}
    db area(pt a,pt b,pt c){return (b-a)*(c-a);}
    db shad(pt a,pt b,pt c){return (b-a)/(c-a);}
    db sqr(db x){return x*x;}
    db dis(pt a,pt b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
    bool cmp(pt a,pt b){return sig(a.x-b.x)?a.y<b.y:a.x<b.x;}
    pt p[M],sta[M],rec[5];
    int top,n;
    void in()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    void tubao()
    {
        top=-1;
        sort(p+1,p+1+n);
        for(int i=1;i<=n;++i)
        {
            while(top>0&&sig(area(sta[top-1],sta[top],p[i]))<=0)--top;
            sta[++top]=p[i];
        }
        int k=top;
        for(int i=n-1;i>=1;--i)
        {
            while(top>k&&sig(area(sta[top-1],sta[top],p[i]))<=0)--top;
            sta[++top]=p[i];
        }
    }
    int x[M];
    db fuck(db x){return !sig(x)?fabs(x):x;}
    void ac()
    {
        int le=1,ri=1,up=1;
        db L,R,H,D,tmp,ans=1e60;
        for(int i=0;i<top;++i)
        {
            D=dis(sta[i],sta[i+1]);
            while(sig(area(sta[i],sta[i+1],sta[up])-area(sta[i],sta[i+1],sta[up+1]))<=0)up=(up+1)%top;
            while(sig(shad(sta[i],sta[i+1],sta[ri])-shad(sta[i],sta[i+1],sta[ri+1]))<=0)ri=(ri+1)%top;
            if(i==0)le=up;
            while(sig(shad(sta[i],sta[i+1],sta[le])-shad(sta[i],sta[i+1],sta[le+1]))>=0)le=(le+1)%top;
            L=shad(sta[i],sta[i+1],sta[le])/D;
            R=shad(sta[i],sta[i+1],sta[ri])/D;
            H=area(sta[i],sta[i+1],sta[up])/D;
            H=H>0?H:-H;
            tmp=(R-L)*H;
            if(tmp<ans)
            {
                ans=tmp;
                rec[0]=sta[i]+(sta[i+1]-sta[i])*(R/D);
                rec[1]=rec[0]+(sta[ri]-rec[0])*(H/dis(sta[ri],rec[0]));
                rec[2]=rec[1]-(rec[0]-sta[i])*((R-L)/dis(sta[i],rec[0]));
                rec[3]=rec[2]-(rec[1]-rec[0]);
            }
        }
        ans=fabs(ans);
        printf("%.5lf
    ",ans);
        int fir=0;
        for(int i=1;i<=3;++i)
        if(rec[i]<rec[fir])fir=i;
        for(int i=0;i<=3;++i)
        printf("%.5lf %.5lf
    ",fuck(rec[(i+fir)%4].x),fuck(rec[(i+fir)%4].y));
    }
    int main()
    {
        in();tubao();
        ac();
        return 0;
    }
  • 相关阅读:
    AS将一个项目导入到另一个项目中
    Android Studio出现:Cause: unable to find valid certification path to requested target
    小米手机Toast带app名称
    PopupWindow 点击外部区域无法关闭的问题
    EditText inputType类型整理
    Fragment通过接口回调向父Activity传值
    Android selector一些坑
    Installation failed with message Failed to commit install session 634765663 with command cmd package
    旷视上海研究院机器人方向招聘
    语义SLAM的数据关联和语义定位(四)多目标测量概率模型
  • 原文地址:https://www.cnblogs.com/noip/p/9538341.html
Copyright © 2011-2022 走看看