BZOJ1185 HNOI2007 最小矩形覆盖 凸包、旋转卡壳
首先,肯定只有凸包上的点会限制这个矩形,所以建立凸包。
然后可以知道,矩形上一定有一条边与凸包上的边重合,否则可以转一下使得它重合,答案会更小。
于是沿着凸包枚举这一条边,通过旋转卡壳找到离这条边最远的点以及这个矩形两端的点,这五个点构成的矩形就是一个可能的答案了。
各种判断用向量叉积和点积
注意一下输出\(-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 最小矩形覆盖 凸包、旋转卡壳的更多相关文章
- [BZOJ1185][HNOI2007]最小矩形覆盖-[凸包+旋转卡壳]
Description 传送门 Solution 感性理解一下,最小矩形一定是由一条边和凸包上的边重合的. 然后它就是模板题了..然而真的好难调,小于大于动不动就打错. Code #include&l ...
- BZOJ1185[HNOI2007] 最小矩形覆盖(旋转卡壳)
BZOJ1185[HNOI2007] 最小矩形覆盖 题面 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点的坐标 分析 首先可以先求凸包,因为覆盖了凸包上的顶点,凸 ...
- BZOJ1185 [HNOI2007]最小矩形覆盖 【旋转卡壳】
题目链接 BZOJ1185 题解 最小矩形一定有一条边在凸包上,枚举这条边,然后旋转卡壳维护另外三个端点即可 计算几何细节极多 维护另外三个端点尽量不在这条边上,意味着左端点尽量靠后,右端点尽量靠前, ...
- bzoj 1185 [HNOI2007]最小矩形覆盖 凸包+旋转卡壳
题目大意 用最小矩形覆盖平面上所有的点 分析 有一结论:最小矩形中有一条边在凸包的边上,不然可以旋转一个角度让面积变小 简略证明 我们逆时针枚举一条边 用旋转卡壳维护此时最左,最右,最上的点 注意 注 ...
- 2018.10.18 bzoj1185: [HNOI2007]最小矩形覆盖(旋转卡壳)
传送门 不难看出最后的矩形一定有一条边与凸包某条边重合. 因此先求出凸包,然后旋转卡壳求出当前最小矩形面积更新答案. 代码: #include<bits/stdc++.h> #define ...
- [HNOI2007][BZOJ1185] 最小矩形覆盖 [凸包+旋转卡壳]
题面 BZOJ题面 前置芝士 建议先学习向量相关的计算几何基础 计算几何基础戳这里 思路 用这道题学习一下凸包和旋转卡壳 首先是凸包部分 凸包 求凸包用的算法是graham算法 算法流程如下: 找到$ ...
- bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包
[HNOI2007]最小矩形覆盖 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 2081 Solved: 920 ...
- BZOJ1185 : [HNOI2007]最小矩形覆盖
求出凸包后,矩形的一条边一定与凸包的某条边重合. 枚举每条边,求出离它最远的点和离它最左最右的点,因为那三个点是单调变化的,所以复杂度为$O(n)$. 注意精度. #include<cstdio ...
- bzoj千题计划209:bzoj1185: [HNOI2007]最小矩形覆盖
http://www.lydsy.com/JudgeOnline/problem.php?id=1185 题解去看它 http://www.cnblogs.com/TheRoadToTheGold/p ...
随机推荐
- python之管道, 事件, 信号量, 进程池
管道:双向通信 2个进程之间相互通信 from multiprocessing import Process, Pipe def f1(conn): from_zjc_msg = conn.recv( ...
- PyCharm实现高效远程调试代码
PyCharm实现高效远程调试代码 (薛刚强) 为方便Python代码学习和项目开发,目前选择专业的 IDE 开发工具 ,如 PyCham.针对个人使用的技巧做个笔记,分享给大家,有描述 ...
- Linux vsftd配置文件
vi /etc/vsftpd.conf listen=YES userlist_deny=NO userlist_enable=YES anonymous_enable=YES local_enabl ...
- Java:[面向对象:继承,多态]
本文内容: 继承 多态 首发时期:2018-03-23 继承: 介绍: 如果多个类中存在相同的属性和行为,可以将这些内容抽取到单独一个类中,那么多个类(子类)无需再定义这些属性和行为,只要继承那个类( ...
- python爬虫之Beautifulsoup学习笔记
相关内容: 什么是beautifulsoup bs4的使用 导入模块 选择使用解析器 使用标签名查找 使用find\find_all查找 使用select查找 首发时间:2018-03-02 00:1 ...
- C语言程序试题
一个无向连通图G点上的哈密尔顿(Hamiltion)回路是指从图G上的某个顶点出发,经过图上所有其他顶点一次且仅一次,最后回到该顶点的路劲.一种求解无向图上哈密尔顿回路算法的基础实现如下: 假设图G存 ...
- sql 删除默认索引,对象 依赖于 列,由于一个或多个对象访问此列
declare @name varchar(50)select @name =b.name from sysobjects b join syscolumns aon b.id = a.cdefau ...
- FUSE 文件系统 example部分 源码注释 (libfuse 2.9.9)
本篇文章主要是针对fuse-2.9.9 Example 部分 给出的源码,结合官方文档,以及网上的资料给出注释,希望能给正在学习的你们一点帮助. Hello.c /* FUSE: Filesystem ...
- [MapReduce_add_3] MapReduce 通过分区解决数据倾斜
0. 说明 数据倾斜及解决方法的介绍与代码实现 1. 介绍 [1.1 数据倾斜的含义] 大量数据发送到同一个节点进行处理,造成此节点繁忙甚至瘫痪,而其他节点资源空闲 [1.2 解决数据倾斜的方式] 重 ...
- 彻底卸载删除Win10易升,禁止再生
易升是微软推出的win10升级工具.用户可通过易升一键升级win10. 因为我的电脑已经是win10的系统,所以我也不需要升级.也不想升级,因为我从网上了解到升级后的系统反而没有升级前的好用. 微软的 ...