传送门


首先,肯定只有凸包上的点会限制这个矩形,所以建立凸包。

然后可以知道,矩形上一定有一条边与凸包上的边重合,否则可以转一下使得它重合,答案会更小。

于是沿着凸包枚举这一条边,通过旋转卡壳找到离这条边最远的点以及这个矩形两端的点,这五个点构成的矩形就是一个可能的答案了。

各种判断用向量叉积和点积

注意一下输出\(-0.0000\)的情况

#include<bits/stdc++.h>
#define ld long double
#define eps 1e-8
//This code is written by Itst
using namespace std;

const int MAXN = 5e4 + 10;
struct vec{
    ld x , y;
    vec(ld _x = 0 , ld _y = 0){x = _x; y = _y;}
    bool operator <(const vec a)const{
        return x < a.x;
    }
    vec operator -(vec a){
        return vec(x - a.x , y - a.y);
    }
    vec operator *(ld p){
        return vec(p * x , p * y);
    }
    vec operator +(vec a){
        return vec(x + a.x , y + a.y);
    }
}now[MAXN] , temp[MAXN] , squ[4];
int cnt , N , top , st[MAXN] , ind[MAXN];
ld ans;

inline bool cmp(ld a , ld b){
    return a - eps < b && a + eps > b;
}

inline ld cot(vec a , vec b){
    return a.x * b.y - a.y * b.x;
}

inline ld dot(vec a , vec b){
    return a.x * b.x + a.y * b.y;
}

inline ld calS(vec a , vec b , vec c){
    return fabs(cot(c - a , b - a));
}

inline ld len(vec a){
    return sqrt(a.x * a.x + a.y * a.y);
}

inline ld calS(vec a , vec b , vec c , vec d , vec e){
    return calS(a , d , b) / len(b - a) * dot(c - e , b - a) / len(b - a);
}

inline vec rev(vec a){
    return vec(-a.y , a.x);
}

void input(){
    cin >> N;
    for(int i = 1 ; i <= N ; ++i)
        cin >> now[i].x >> now[i].y;
}

void init(){
    ans = 1e18;
    sort(now + 1 , now + N + 1);
    for(int i = 1 ; i <= N ; ++i){
        while(top >= 2 && cot(now[i] - now[st[top - 1]] , now[st[top]] - now[st[top - 1]]) > -eps)
            --top;
        st[++top] = i;
    }
    for(int i = 1 ; i <= top ; ++i)
        ind[++cnt] = st[i];
    top = 0;
    for(int i = N ; i ; --i){
        while(top >= 2 && cot(now[i] - now[st[top - 1]] , now[st[top]] - now[st[top - 1]]) > -eps)
            --top;
        st[++top] = i;
    }
    for(int i = 2 ; i < top ; ++i)
        ind[++cnt] = st[i];
    for(int i = 1 ; i <= cnt ; ++i)
        temp[i] = now[ind[i]];
    memcpy(now + 1 , temp + 1 , sizeof(vec) * cnt);
}

void work(){
    int minX = 1 , maxX = 1 , minY = 1 , maxY = 1;
    for(int i = 2 ; i <= N ; ++i){
        if(now[minX].x > now[i].x)
            minX = i;
        if(now[maxX].x < now[i].x)
            maxX = i;
        if(now[minY].y > now[i].y)
            minY = i;
        if(now[maxY].y < now[i].y)
            maxY = i;
    }
    ans = (now[maxY].y - now[minY].y) * (now[maxX].x - now[minX].x);
    squ[0].x = squ[3].x = now[minX].x;
    squ[1].x = squ[2].x = now[maxX].x;
    squ[0].y = squ[1].y = now[minY].y;
    squ[2].y = squ[3].y = now[maxY].y;
    for(int i = 1 ; i <= cnt ; minY = minY % cnt + 1 , ++i){
        while(calS(now[minY] , now[maxY] , now[minY % cnt + 1]) < calS(now[minY] , now[maxY % cnt + 1] , now[minY % cnt + 1]))
            maxY = maxY % cnt + 1;
        while(dot(now[minY % cnt + 1] - now[minY] , now[minX % cnt + 1] - now[minX]) < eps)
            minX = minX % cnt + 1;
        while(dot(now[minY % cnt + 1] - now[minY] , now[maxX % cnt + 1] - now[maxX]) > -eps)
            maxX = maxX % cnt + 1;
        ld t = calS(now[minY] , now[minY % cnt + 1] , now[maxX] , now[maxY] , now[minX]);
        if(t < ans){
            ans = t;
            squ[0] = (now[minY % cnt + 1] - now[minY]) * (dot(now[minY] - now[maxX] , now[minY] - now[minY % cnt + 1]) / len(now[minY] - now[minY % cnt + 1]) / len(now[minY] - now[minY % cnt + 1])) + now[minY];
            squ[1] = rev(now[minY % cnt + 1] - now[minY]) * (calS(now[minY] , now[minY % cnt + 1] , now[maxY]) / len(now[minY] - now[minY % cnt + 1]) / len(now[minY] - now[minY % cnt + 1])) + squ[0];
            squ[2] = (now[minY] - now[minY % cnt + 1]) * (t / len(squ[1] - squ[0]) / len(now[minY % cnt + 1] - now[minY])) + squ[1];
            squ[3] = squ[2] + (squ[0] - squ[1]);
        }
    }
}

void output(){
    cout << fixed << setprecision(5) << (ans < 1e-5 ? 0 : ans) << endl;
    int dir = 0;
    for(int j = 1 ; j < 4 ; ++j)
        if(squ[dir].y > squ[j].y || cmp(squ[dir].y , squ[j].y) && squ[j].x < squ[dir].x)
            dir = j;
    for(int i = 0 ; i < 4 ; ++i)
        cout << fixed << setprecision(5) << (squ[(dir + i) % 4].x < 1e-5 ? 0 : squ[(dir + i) % 4].x) << ' ' << (squ[(dir + i) % 4].y < 1e-5 ? 0 : squ[(dir + i) % 4].y) << endl;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in" , "r" , stdin);
    //freopen("out" , "w" , stdout);
#endif
    input();
    init();
    work();
    output();
    return 0;
}

BZOJ1185 HNOI2007 最小矩形覆盖 凸包、旋转卡壳的更多相关文章

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

    Description 传送门 Solution 感性理解一下,最小矩形一定是由一条边和凸包上的边重合的. 然后它就是模板题了..然而真的好难调,小于大于动不动就打错. Code #include&l ...

  2. BZOJ1185[HNOI2007] 最小矩形覆盖(旋转卡壳)

    BZOJ1185[HNOI2007] 最小矩形覆盖 题面 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点的坐标 分析 首先可以先求凸包,因为覆盖了凸包上的顶点,凸 ...

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

    题目链接 BZOJ1185 题解 最小矩形一定有一条边在凸包上,枚举这条边,然后旋转卡壳维护另外三个端点即可 计算几何细节极多 维护另外三个端点尽量不在这条边上,意味着左端点尽量靠后,右端点尽量靠前, ...

  4. bzoj 1185 [HNOI2007]最小矩形覆盖 凸包+旋转卡壳

    题目大意 用最小矩形覆盖平面上所有的点 分析 有一结论:最小矩形中有一条边在凸包的边上,不然可以旋转一个角度让面积变小 简略证明 我们逆时针枚举一条边 用旋转卡壳维护此时最左,最右,最上的点 注意 注 ...

  5. 2018.10.18 bzoj1185: [HNOI2007]最小矩形覆盖(旋转卡壳)

    传送门 不难看出最后的矩形一定有一条边与凸包某条边重合. 因此先求出凸包,然后旋转卡壳求出当前最小矩形面积更新答案. 代码: #include<bits/stdc++.h> #define ...

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

    题面 BZOJ题面 前置芝士 建议先学习向量相关的计算几何基础 计算几何基础戳这里 思路 用这道题学习一下凸包和旋转卡壳 首先是凸包部分 凸包 求凸包用的算法是graham算法 算法流程如下: 找到$ ...

  7. bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包

    [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 2081  Solved: 920 ...

  8. BZOJ1185 : [HNOI2007]最小矩形覆盖

    求出凸包后,矩形的一条边一定与凸包的某条边重合. 枚举每条边,求出离它最远的点和离它最左最右的点,因为那三个点是单调变化的,所以复杂度为$O(n)$. 注意精度. #include<cstdio ...

  9. bzoj千题计划209:bzoj1185: [HNOI2007]最小矩形覆盖

    http://www.lydsy.com/JudgeOnline/problem.php?id=1185 题解去看它 http://www.cnblogs.com/TheRoadToTheGold/p ...

随机推荐

  1. java Name [jdbc/myjavadb] is not bound in this Context. Unable to find [jdbc].

    一.出错时的情况: 首先,这是一个servlet项目 1.项目的web.xml配置了:(后来发现不配置这个也行,但是tomcat一定要配置) <resource-ref> <desc ...

  2. php使用PHPexcel类读取excel文件(循环读取每个单元格的数据)

    error_reporting(E_ALL); date_default_timezone_set('Asia/ShangHai'); include_once('Classes/PHPExcel/I ...

  3. vue.js及项目实战[笔记]— 01 vue.js

    一. vue基础 1. 历史介绍 angular 09年,年份较早,一开始大家是拒绝的 react 2013年,用户体验较好,直接拉到一堆粉丝 vue 2014年,用户体验较好 前端框架与库的区别 j ...

  4. ArcGIS地图文档优化 mxdPerfstat工具使用体验

    经常有客户会咨询到如何提高地图的显示性能.为何ArcMap刷新地图那么缓慢.为何地图服务响应要等待10多秒? 诸如这些问题,虽然它们的表象都是相似的,但是往往在分析排查问题的时候,我们发现背后的原因是 ...

  5. 单元测试工具Junit浅谈

    什么是单元测试?   写了一个类和一些方法,给别人用,会不会有bug?那就测一下这些方法吧 怎么测?   用main方法测?不能一起运行,需要人为观察输出是否正确,测试效率低 单元测试能带来什么好处? ...

  6. mybatis学习系列二

    1 参数处理(封装map过程)(23) 1.1)F5进入断点:Employee employee1=mapper.selectEmployeeByMap(map); 1.2)进入MapperProxy ...

  7. Spring Boot 使用 ServletFileUpload上传文件失败,upload.parseRequest(request)为空

    使用Apache Commons FileUpload组件上传文件时总是返回null,调试发现ServletFileUpload对象为空,在Spring Boot中有默认的文件上传组件,在使用Serv ...

  8. Java中常用的字节流和字符流

    IO流(输入流.输出流) 字节流.字符流 1.字节流: InputStream.OutputStream InputStream抽象了应用程序读取数据的方式: OutputStream抽象了应用程序写 ...

  9. php解决前后端验证字符串长度不一致

    前端代码 function getStrleng(str){ var myLen =0; for(var i=0;i<str.length;i++){ if(str.charCodeAt(i)& ...

  10. 05LaTeX学习系列之---TeX的命令行操作

    目录 目录 前言 (一)查看版本号 1.查看TeX的版本号 2.查看LaTeX的版本号 3.查看XeLeTeX的版本号 (二)更行版本 (三)用命令行来编译.tex文件 1.用LaTeX编译 2.用X ...