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;
    }
  • 相关阅读:
    HUE配置HBase
    HUE配置HIVE
    HUE配置hadoop
    HUE的安装
    CM (Cloudera Manager) 的安装,便于CDH的离线部署
    MapReduce -- 最短路径
    Mapreduce -- PageRank
    CentOS 建立本地yum源服务器
    js移动设备手机跳转地址代码
    离线存储
  • 原文地址:https://www.cnblogs.com/noip/p/9538341.html
Copyright © 2011-2022 走看看