【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\n",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\n",ans[i].x,ans[i].y);
    for(int i=0;i<mni;i++) printf("%.5lf %.5lf\n",ans[i].x,ans[i].y);
}

int main()
{
    init();
    graham_scan();
    work();

    return 0; 
}
posted @ 2018-06-09 11:45  Maxwei_wzj  阅读(100)  评论(0编辑  收藏  举报