[BZOJ1185][HNOI2007]最小矩形覆盖-[凸包+旋转卡壳]

Description

传送门

Solution

感性理解一下,最小矩形一定是由一条边和凸包上的边重合的。

然后它就是模板题了。。然而真的好难调,小于大于动不动就打错。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-9;
int n;
struct node{double x,y;
    friend node operator +(node a,node b){return node{a.x+b.x,a.y+b.y};}
    friend node operator -(node a,node b){return node{a.x-b.x,a.y-b.y};}
    friend double operator *(node a,node b){return a.x*b.y-a.y*b.x;}
    friend double operator /(node a,node b){return a.x*b.x+a.y*b.y;}
    friend node operator *(node a,double b) {return node{a.x*b,a.y*b};}
    friend bool operator <(node a,node b) { return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y;}
}p[50010],st[50010],low;
double dis(node a){return a.x*a.x+a.y*a.y;}
bool cmp(node a,node b){
    double t=(a-p[1])*(b-p[1]);
    if (fabs(t)<eps) return dis(a-p[1])<dis(b-p[1]);
    return t>0;
}
int top=0,now;
int main()
{
    scanf("%d",&n);
    low.x=low.y=2147483647;
    scanf("%lf%lf",&p[1].x,&p[1].y);
    for (int i=2;i<=n;i++)
    {
        scanf("%lf%lf",&p[i].x,&p[i].y);    
        if (p[i]<p[1]) swap(p[i],p[1]);    
    }
    sort(p+2,p+n+1,cmp);
    st[++top]=p[1];
    for (int i=2;i<=n;i++)
    {
        while (top>1&&(st[top]-st[top-1])*(p[i]-st[top])<eps) top--;
        st[++top]=p[i];
    }
    st[0]=st[top];
    node pr[4];
    double L,R,D,H,ans=1e10;int l=1,r=1,now=1;
    for (int i=0;i<top;i++)
    {
        D=sqrt(dis(st[i]-st[i+1]));
        while ((st[i+1]-st[i])*(st[now+1]-st[i])>(st[i+1]-st[i])*(st[now]-st[i])-eps) now=(now+1)%top;
        while ((st[i+1]-st[i])/(st[r+1]-st[i])>(st[i+1]-st[i])/(st[r]-st[i])-eps) r=(r+1)%top;
        if (!i) l=r;
        while ((st[i+1]-st[i])/(st[l+1]-st[i])<(st[i+1]-st[i])/(st[l]-st[i])+eps) l=(l+1)%top;
        L=(st[i+1]-st[i])/(st[l]-st[i])/D;R=(st[i+1]-st[i])/(st[r]-st[i])/D;
        H=abs((st[i+1]-st[i])*(st[now]-st[i])/D);
        if ((R-L)*H<ans)
        {
            ans=(R-L)*H;
            pr[0]=st[i]+(st[i+1]-st[i])*(R/D);
            pr[1]=pr[0]+(st[r]-pr[0])*(H/sqrt(dis(pr[0]-st[r])));
            pr[2]=pr[1]-(pr[0]-st[i])*((R-L)/sqrt(dis(st[i]-pr[0])));
            pr[3]=pr[2]-(pr[1]-pr[0]);
        }
    }
    now=0;
    for (int i=1;i<=3;i++) if (pr[i]<pr[now]) now=i;
    printf("%.5f\n",ans);
    for (int i=0;i<=3;i++) 
    {
        if (pr[(i+now)%4].x>-5*1e-6) pr[(i+now)%4].x=fabs(pr[(i+now)%4].x);
        if (pr[(i+now)%4].y>-5*1e-6) pr[(i+now)%4].y=fabs(pr[(i+now)%4].y);
        printf("%.5f %.5f\n",pr[(i+now)%4].x,pr[(i+now)%4].y);
    }
}

猜你喜欢

转载自www.cnblogs.com/coco-night/p/9496560.html