【[HNOI2007]最小矩形覆盖】旋转卡壳

旋转卡壳,orz orz orz

luogu3187

题目描述

给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点坐标

输入输出格式

输入格式: 第一行为一个整数n(3<=n<=50000),从第2至第n+1行每行有两个浮点数,表示一个顶点的x和y坐标,不用科学计数法 输出格式: 第一行为一个浮点数,表示所求矩形的面积(精确到小数点后5位),接下来4行每行表示一个顶点坐标,要求第一行为y坐标最小的顶点,其后按逆时针输出顶点坐标.如果用相同y坐标,先输出最小x坐标的顶点

输入输出样例

输入样例#1: 复制
6 1.0 3.00000

1 4.00000

2.0000 1

3 0.0000

3.00000 6

6.0 3.0
输出样例#1: 复制
18.00000

3.00000 0.00000

6.00000 3.00000

3.00000 6.00000

0.00000 3.00000

说明

感谢 @intruder 提供题目简述
由于某个神奇的结论,一定会有一条边在凸壳上,枚举每条凸壳上的边。那么对于这条边的对面有一个对锺点(即高最大,叉积最大),由于显然位置单调,利用叉积卡壳单调枚举即可,类似的可以利用点积最小和最大的点可以找出最左点和最右点,这样就保证可以覆盖所有点,然后略用一点初中几何知识,就可以了。 极度卡精度orz
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>

using namespace std;
typedef double db;
const int maxn = 5e5+5;
const db eps = 1e-8;
struct node{
    db x,y;
    friend db operator*(node aa,node bb) {
        return aa.x*bb.x + aa.y*bb.y;
    }
    friend node operator*(node aa,db bb) {
        return (node){aa.x*bb,aa.y*bb};
    }
    friend db operator^(node aa,node bb) {
        return aa.x*bb.y - aa.y*bb.x;
    }
    friend node operator+(node aa,node bb) {
        return (node){aa.x+bb.x,aa.y+bb.y};
    }
    friend node operator-(node aa,node bb) {
        return (node){aa.x-bb.x,aa.y-bb.y};
    }
    friend db dis(node aa) {
        return sqrt(aa.x*aa.x+aa.y*aa.y);
    }
    friend db chaji(node aa,node bb,node cc) {
        return (bb-aa)^(cc-aa);
    }
    friend db diji(node aa,node bb,node cc) {
        return (bb-aa)*(cc-aa);
    }
    friend bool CP(node aa,node bb) { // aa < bb ? 1 : 0
        if( fabs(aa.y-bb.y)>eps ) return aa.y < bb.y;
        return aa.x < bb.x;
    }
}z[maxn],s[maxn],as[10]; int tp; db ans=1e18;;

bool cmp(node aa,node bb) {
    return aa.x < bb.x;
}
int n;
void gethull() {
    sort(z+1,z+1+n,cmp);
    for(int i=1;i<=n;i++) {
        while(tp>1&&( (s[tp]-s[tp-1])^(z[i]-s[tp-1]) )<=0 ) tp--;
        s[++tp] = z[i];
    }
    int tmp = tp;
    for(int i=n-1;i>=1;i--) {
        while(tp>tmp&&( (s[tp]-s[tp-1])^(z[i]-s[tp-1]) )<=0) tp--;
        s[++tp] = z[i];
    }
	--tp;
    s[tp+1] = s[1];
}
void kaker() {
    int p,l,r; p = l = r = 2;
    for(int i=1;i<tp;i++) {
        while( fabs(chaji(s[i],s[i+1],s[p+1])) > fabs(chaji(s[i],s[i+1],s[p])) - eps ) p = p%tp+1;
        while( diji(s[i],s[i+1],s[r+1]) > diji(s[i],s[i+1],s[r]) - eps ) r = r%tp+1;
        if(i==1) l = r;
        while( diji(s[i],s[i+1],s[l+1]) < diji(s[i],s[i+1],s[l]) + eps ) l = l%tp+1;
        db dd = dis(s[i]-s[i+1]);
        db lcd = diji(s[i],s[i+1],s[l])/dd;
        db rcd = diji(s[i],s[i+1],s[r])/dd;
        db hh = fabs( chaji(s[i],s[i+1],s[p])/dd );
        if(ans>hh*(rcd-lcd)) {
            ans = hh*(rcd-lcd);
            as[1] = s[i] + (s[i+1]-s[i])*(rcd/dd);
            as[2] = as[1] + (s[r]-as[1])*(hh/dis(s[r]-as[1]));
            as[3] = as[2] - (as[1]-s[i])*((rcd-lcd)/rcd);
            as[4] = as[3] + as[1] - as[2];
        }
    }
}
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%lf%lf",&z[i].x,&z[i].y);
    }
    gethull();
    kaker();
    printf("%.5f\n",ans);
    int fi = 1;
    for(int i=2;i<=4;i++) {
        if(CP(as[i],as[fi])) fi = i;
    }
    for(int i=fi;i<=4;i++) {
        printf("%.5f %.5f\n",floor(as[i].x+0.5),floor(as[i].y+0.5) );
    }
    for(int i=1;i<fi;i++) {
        printf("%.5f %.5f\n",floor(as[i].x+0.5),floor(as[i].y+0.5));
    }
}
 
posted @ 2019-01-03 13:44  Newuser233  阅读(9)  评论(0)    收藏  举报