[HNOI2007]最小矩形覆盖

Description

给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,

输出所求矩形的面积和四个顶点坐标

Input

第一行为一个整数n(3<=n<=50000)

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

Output

第一行为一个浮点数,表示所求矩形的面积(精确到小数点后5位),

接下来4行每行表示一个顶点坐标,要求第一行为y坐标最小的顶点,

其后按逆时针输出顶点坐标.如果用相同y坐标,先输出最小x坐标的顶点

Sample Input

6 1.0 3.00000

1 4.00000

2.0000 1

3 0.0000

3.00000 6

6.0 3.0

Sample Output

18.00000

3.00000 0.00000

6.00000 3.00000

3.00000 6.00000

0.00000 3.00000

Solution

说实话这个题笔者做的实在是非常难受身心俱疲。首先之前打过一遍然后挂了,怎么调都调不出来之后又重构代码,然后又是各种调不出来,之后过了样例,又是各种wa,什么特判都加完了之后终于是A掉了。。。

总体思路大致是这个样子,经过一系列奇奇怪怪的证明之后我们可以发现,我们要求的那个矩形一定有一条边在这些点的凸包的边上,然后旋转卡壳枚举边,求出来就可以了,代码非常难搞,细节非常多,笔者一开始被卡掉了0.0001的精度,结果找着黄学长的一顿乱改,结果改到最后,快长得一样了。。。。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define inf 50000000
#define re register
#define MAXN 50005
#define eps 1e-8
using namespace std;
double ans=1e60;
int n,top;
struct P{
    double x,y;
    P(){}
    P(double _x,double _y):x(_x),y(_y){}
    friend bool operator<(P a,P b){
        return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y;
    }
    friend bool operator==(P a,P b){
        return fabs(a.x-b.x)<eps&&fabs(a.y<b.y)<eps;
    }
    friend bool operator!=(P a,P b){
        return !(a==b);
    }
    friend P operator+(P a,P b){
        return P(a.x+b.x,a.y+b.y);
    }
    friend P operator-(P a,P b){
        return P(a.x-b.x,a.y-b.y);
    }
    friend double operator *(P a,P b){
        return a.x*b.y-a.y*b.x;
    }
    friend P operator *(P a,double b){
        return P(a.x*b,a.y*b);
    }
    friend double operator /(P a,P b){
        return a.x*b.x+a.y*b.y;
    }
    friend double dis(P a){
        return sqrt(a.x*a.x+a.y*a.y);
    }
};
P p[MAXN],q[MAXN],t[5];
inline bool cmp(P a,P b)
{
    double k=(a-p[1])*(b-p[1]);
    if(fabs(k)<eps) return dis(p[1]-a)-dis(p[1]-b)<0;
    return k>0;
}
inline void Graham()
{
    for(re int i=2;i<=n;i++)
        if(p[i]<p[1]) swap(p[i],p[1]);
    sort(p+2,p+n+1,cmp);
    q[++top]=p[1];
    for(re int i=2;i<=n;i++){
        while(top>1&&(q[top]-q[top-1])*(p[i]-q[top])<eps) top--;
        q[++top]=p[i];
    }
    q[0]=q[top];
}
inline void solve()
{
    int l=1,r=1,p=1;
    double L,R,D,H;
    for(re int i=0;i<top;i++){
        D=dis(q[i]-q[i+1]);
        while((q[i+1]-q[i])*(q[p+1]-q[i])-(q[i+1]-q[i])*(q[p]-q[i])>-eps) p=(p+1)%top;
        while((q[i+1]-q[i])/(q[r+1]-q[i])-(q[i+1]-q[i])/(q[r]-q[i])>-eps) r=(r+1)%top;
        if(i==0) l=r;
        while((q[i+1]-q[i])/(q[l+1]-q[i])-(q[i+1]-q[i])/(q[l]-q[i])<eps) 
        l=(l+1)%top;
        L=(q[i+1]-q[i])/(q[l]-q[i])/D;
        R=(q[i+1]-q[i])/(q[r]-q[i])/D;
        H=(q[i+1]-q[i])*(q[p]-q[i])/D;
        if(H<0) H=-H;
        double tmp=(R-L)*H;
        if(tmp<ans)
        {
            ans=tmp;
            t[0]=q[i]+(q[i+1]-q[i])*(R/D);
            t[1]=t[0]+(q[r]-t[0])*(H/dis(t[0]-q[r]));
            t[2]=t[1]-(t[0]-q[i])*((R-L)/dis(q[i]-t[0]));
            t[3]=t[2]-(t[1]-t[0]);
        }
    }
}
int main()
{
    cin>>n;
    for(re int i=1;i<=n;i++)
        scanf("%lf%lf",&p[i].x,&p[i].y);
    Graham();
    solve();
    printf("%.5lf\n" ,ans);
    int fir=0;
    for(re int i=1;i<=3;i++)
        if(t[i]<t[fir])
            fir=i;
    for(re int i=0;i<=3;i++)
        printf("%.5lf %.5lf\n",fabs(t[(i+fir)%4].x)>1e-12?t[(i+fir)%4].x:0.00000,fabs(t[(i+fir)%4].y)>1e-12?t[(i+fir)%4].y:0.00000);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/victorique/p/8946514.html