zoukankan      html  css  js  c++  java
  • 【BZOJ1185】最小矩形覆盖(HNOI2007)-旋转卡壳

    测试地址:最小矩形覆盖
    做法:本题需要用到旋转卡壳。
    根据直觉(实际上是我不会证),最小的矩形的一边一定在凸包上,于是我们在凸包上枚举其中的一边,顺便开三个指针求出对踵点,以及在当前边方向上最远的两个点,即可求出矩形挨着的点,这样就可以求出矩形的其它三个点了。于是我们就解决了这一题,求凸包的时间复杂度为O(nlogn),后面算法的时间复杂度为O(n)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const double eps=1e-8;
    int n,top,st[100010];
    struct point
    {
        double x,y;
    }p[50010],ans[4],now[4];
    
    point operator + (point a,point b) {point s={a.x+b.x,a.y+b.y};return s;}
    point operator - (point a,point b) {point s={a.x-b.x,a.y-b.y};return s;}
    point operator * (point a,double b) {point s={a.x*b,a.y*b};return s;}
    double operator * (point a,point b) {return a.x*b.y-a.y*b.x;}
    
    double dis(point a,point b)
    {
        return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    }
    
    bool cmp(point a,point b)
    {
        if (fabs((a-p[1])*(b-p[1]))<eps)
            return dis(a,p[1])<dis(b,p[1]);
        else return (a-p[1])*(b-p[1])>0;
    }
    
    void init()
    {
        scanf("%d",&n);
    
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
            if (i>1&&(p[i].x<p[1].x||(p[i].x-p[1].x<eps&&p[i].y<p[1].y)))
                swap(p[1],p[i]);
        }
    
        sort(p+2,p+n+1,cmp);
    }
    
    void graham_scan()
    {
        st[1]=top=1;
        for(int i=2;i<=n;i++)
        {
            while(top>1&&(p[st[top]]-p[st[top-1]])*(p[i]-p[st[top]])<eps) top--;
            st[++top]=i;
        }
    }
    
    point inter(point p,point v,point q,point w)
    {
        point u=p-q;
        double t=(w*u)/(v*w);
        return p+v*t;
    }
    
    void work()
    {
        for(int i=1;i<=top;i++)
            st[top+i]=st[top*2+i]=st[top*3+i]=st[i];
    
        st[0]=st[top];
        int x=0,y=2,z=1;
        double mn=1e18;
        for(int i=1;i<=top;i++)
        {
            point p1,p2,p3,p4;
            p1=p[st[i+1]]-p[st[i]];
            p2.x=-p1.y,p2.y=p1.x;
            p3.x=-p1.x,p3.y=-p1.y;
            p4.x=-p2.x,p4.y=-p2.y;
            while(p3*(p[st[z+1]]-p[st[z]])<eps) z++;
            if (i==1) x=z;
            while(p4*(p[st[x+1]]-p[st[x]])<eps) x++;
            while(p2*(p[st[y+1]]-p[st[y]])<eps) y++;
    
            now[0]=inter(p[st[i]],p1,p[st[y]],p2);
            now[1]=inter(p[st[y]],p2,p[st[z]],p3);
            now[2]=inter(p[st[z]],p3,p[st[x]],p4);
            now[3]=inter(p[st[x]],p4,p[st[i]],p1);
            if ((now[1]-now[0])*(now[3]-now[0])<mn)
            {
                mn=(now[1]-now[0])*(now[3]-now[0]);
                for(int i=0;i<4;i++) ans[i]=now[i];
            }
        }
    
        printf("%.5lf
    ",mn);
        double mnx=1e18,mny=1e18;
        int mni;
        for(int i=0;i<4;i++)
            if (ans[i].y<mny||(ans[i].y-mny<eps&&ans[i].x<mnx))
            {
                mnx=ans[i].x;
                mny=ans[i].y;
                mni=i;
            }
        for(int i=mni;i<4;i++) printf("%.5lf %.5lf
    ",ans[i].x,ans[i].y);
        for(int i=0;i<mni;i++) printf("%.5lf %.5lf
    ",ans[i].x,ans[i].y);
    }
    
    int main()
    {
        init();
        graham_scan();
        work();
    
        return 0; 
    }
  • 相关阅读:
    JAVA 面向对象的扩展 内部类
    对于win10 更换JDK后 查询JDK路径还是原路径的解决办法
    懂得的懂
    稀疏数组转化二维数组
    Flume的安装配置
    CentOS7配置ip和ssh免密登录和hadoop环境
    AOP的使用和事务
    spring的个人理解
    单车月结算2-修改和删除功能
    单车月结算1
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793341.html
Copyright © 2011-2022 走看看