BZOJ 1185 [HNOI2007]最小矩形覆盖:凸包 + 旋转卡壳
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1185
题意:
给出二维平面上的n个点,问你将所有点覆盖的最小矩形面积。
题解:
先找出凸包,然后旋转卡壳。
在旋转卡壳中有一个结论:最小覆盖矩形一定有一条边在凸包上。
所以先枚举矩形在凸包上的那条边(p[i],p[i+1]),然后利用单调性找出p[i]的对踵点p[u]。
至于左右两侧的切点p[l]和p[r],要利用它们连线在直线(p[i],p[i+1])上投影长度的单调性求出。
最后将找出的矩形顶点再做一遍极角排序即可。
AC Code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define MAX_N 50005
#define INF_LF 1e14
#define EPS 1e-7 using namespace std; struct Coor
{
double x,y;
Coor(double _x,double _y) { x=_x,y=_y; }
Coor(){}
friend Coor operator + (const Coor &a,const Coor &b)
{
return Coor(a.x+b.x,a.y+b.y);
}
friend Coor operator - (const Coor &a,const Coor &b)
{
return Coor(a.x-b.x,a.y-b.y);
}
friend Coor operator * (const Coor &a,double b)
{
return Coor(a.x*b,a.y*b);
}
friend Coor operator / (const Coor &a,double b)
{
return Coor(a.x/b,a.y/b);
}
friend double len(const Coor &a,const Coor &b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
friend double dot(const Coor &a,const Coor &b)
{
return a.x*b.x+a.y*b.y;
}
friend double cross(const Coor &a,const Coor &b)
{
return a.x*b.y-a.y*b.x;
}
friend double area(const Coor &a,const Coor &b,const Coor &c)
{
return fabs(cross(b-a,c-a));
}
friend double length(const Coor &a)
{
return sqrt(dot(a,a));
}
friend double pro(const Coor &a,const Coor &b)
{
return dot(a,b)/length(b);
}
friend Coor proc(const Coor &a,const Coor &b,const Coor &c)
{
Coor v=c-b;
return b+v*dot(v,a-b)/dot(v,v);
}
}; int n,tot=;
double ans=INF_LF;
Coor p[MAX_N];
Coor con[MAX_N];
Coor rect[MAX_N]; void read()
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
} bool cmp(const Coor &a,const Coor &b)
{
double c=cross(a-p[],b-p[]);
return c!= ? c> : len(p[],a)<len(p[],b);
} inline bool eq(double x,double y)
{
return fabs(x-y)<EPS;
} void graham()
{
for(int i=;i<=n;i++)
{
if(p[i].y<p[].y || (p[i].y==p[].y && p[i].x<p[].x))
{
swap(p[i],p[]);
}
}
sort(p+,p++n,cmp);
con[++tot]=p[],con[++tot]=p[];
for(int i=;i<=n;i++)
{
while(tot>= && cross(con[tot]-con[tot-],p[i]-con[tot])<=) tot--;
con[++tot]=p[i];
}
} inline int mod(int x)
{
return ((x-)%tot+tot)%tot+;
} void rc()
{
int u=,l=,r=;
for(int i=;i<=tot;i++)
{
if(con[i].x<con[l].x || (con[i].x==con[l].x && con[i].y>con[l].y)) l=i;
if(con[i].x>con[r].x || (con[i].x==con[r].x && con[i].y<con[r].y)) r=i;
}
for(int i=;i<=tot;i++)
{
while(area(con[i],con[mod(i+)],con[u])<area(con[i],con[mod(i+)],con[mod(u+)])) u=mod(u+);
while(pro(con[r]-con[l],con[mod(i+)]-con[i])<pro(con[r]-con[mod(l+)],con[mod(i+)]-con[i])) l=mod(l+);
while(pro(con[r]-con[l],con[mod(i+)]-con[i])<pro(con[mod(r+)]-con[l],con[mod(i+)]-con[i])) r=mod(r+);
double w=pro(con[r]-con[l],con[mod(i+)]-con[i]);
double h=area(con[i],con[mod(i+)],con[u])/length(con[mod(i+)]-con[i]);
if(w*h<ans)
{
ans=w*h;
Coor v=con[mod(i+)]-con[i];
rect[]=proc(con[l],con[i],con[mod(i+)]);
rect[]=proc(con[r],con[i],con[mod(i+)]);
rect[]=proc(con[l],con[u],con[u]+v);
rect[]=proc(con[r],con[u],con[u]+v);
}
}
for(int i=;i<;i++)
{
if(rect[i].y<rect[].y || (rect[i].y==rect[].y && rect[i].x<rect[].x))
{
swap(rect[],rect[i]);
}
}
sort(rect+,rect+,cmp);
for(int i=;i<;i++)
{
if(eq(rect[i].x,)) rect[i].x=;
if(eq(rect[i].y,)) rect[i].y=;
}
} void work()
{
graham();
rc();
printf("%.5f\n",ans);
for(int i=;i<;i++) printf("%.5f %.5f\n",rect[i].x,rect[i].y);
} int main()
{
read();
work();
}
BZOJ 1185 [HNOI2007]最小矩形覆盖:凸包 + 旋转卡壳的更多相关文章
- bzoj 1185 [HNOI2007]最小矩形覆盖 凸包+旋转卡壳
题目大意 用最小矩形覆盖平面上所有的点 分析 有一结论:最小矩形中有一条边在凸包的边上,不然可以旋转一个角度让面积变小 简略证明 我们逆时针枚举一条边 用旋转卡壳维护此时最左,最右,最上的点 注意 注 ...
- [BZOJ1185][HNOI2007]最小矩形覆盖-[凸包+旋转卡壳]
Description 传送门 Solution 感性理解一下,最小矩形一定是由一条边和凸包上的边重合的. 然后它就是模板题了..然而真的好难调,小于大于动不动就打错. Code #include&l ...
- 洛谷 P3187 BZOJ 1185 [HNOI2007]最小矩形覆盖 (旋转卡壳)
题目链接: 洛谷 P3187 [HNOI2007]最小矩形覆盖 BZOJ 1185: [HNOI2007]最小矩形覆盖 Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, ...
- BZOJ 1185: [HNOI2007]最小矩形覆盖 [旋转卡壳]
1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 1435 Solve ...
- BZOJ:1185: [HNOI2007]最小矩形覆盖
1185: [HNOI2007]最小矩形覆盖 这计算几何……果然很烦…… 发现自己不会旋转卡壳,补了下,然后发现求凸包也不会…… 凸包:找一个最左下的点,其他点按照与它连边的夹角排序,然后维护一个栈用 ...
- BZOJ1185[HNOI2007] 最小矩形覆盖(旋转卡壳)
BZOJ1185[HNOI2007] 最小矩形覆盖 题面 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点的坐标 分析 首先可以先求凸包,因为覆盖了凸包上的顶点,凸 ...
- bzoj 1185 [HNOI2007]最小矩形覆盖——旋转卡壳
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1185 矩形一定贴着凸包的一条边.不过只是感觉这样. 枚举一条边,对面的点就是正常的旋转卡壳. ...
- BZOJ 1185: [HNOI2007]最小矩形覆盖-旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标-备忘板子
来源:旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标 BZOJ又崩了,直接贴一下人家的代码. 代码: #include"stdio.h" #include"str ...
- ●BZOJ 1185 [HNOI2007]最小矩形覆盖
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1185 题解: 计算几何,凸包,旋转卡壳 结论:矩形的某一条边在凸包的一条边所在的直线上. ( ...
随机推荐
- Spring使用JMS传递消息的两种方式
方式一:同步收发消息,使用JMS template 消费者阻塞等待消息的到来. 方式二:异步收发消息,使用message listener container 消费者提供一个listener,注册一个 ...
- Storm-源码分析-Topology Submit-Task
mk-task, 比较简单, 因为task只是概念上的结构, 不象其他worker, executor都需要创建进程或线程 所以其核心其实就是mk-task-data, 1. 创建TopologyCo ...
- JSP--JSP语法--指令--include(动态包含/静态包含)--九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构
一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1. JSP模板元素:JSP中HT ...
- linux c编程:记录锁
记录锁相当于线程同步中读写锁的一种扩展类型,可以用来对有亲缘或无亲缘关系的进程进行文件读与写的同步,通过fcntl函数来执行上锁操作.尽管读写锁也可以通过在共享内存区来进行进程的同步,但是fcntl记 ...
- Linux学习笔记(4)磁盘分区(fdisk)、挂载与文件系统命令
Linux学习笔记(4)磁盘分区(fdisk).挂载与文件系统命令 1.磁盘分区是怎么表示的? 1.1 对于IDE接口,第一主盘为hda,第1从盘为hdb,第1从盘的第1个分区为hdb1 1.2 对于 ...
- windows如何安装mysql
参考一下网址,已测试可用 https://www.cnblogs.com/reyinever/p/8551977.html
- PHP 数组教程 定义数组
数组array是一组有序的变量,其中每个变量被叫做一个元素. 一.定义数组 可以用 array() 语言结构来新建一个数组.它接受一定数量用逗号分隔的 key => value 参数对. a ...
- php foreach函数的用法
php foreach函数用法举例. Foreach 函数(PHP4/PHP5) foreach 语法结构提供了遍历数组的简单方式. foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类 ...
- mysql忽略一些错误代码
模拟的故障,在从库中新建一个库,然后主库新建一个与从库相同名字的库,然后进入下面的show Mysql从库复制故障解决 当show slave status:报错 slave_io_running:y ...
- selenium打不开chrome
selenium打不开chrome,出现下面的报错 requests.exceptions.ChunkedEncodingError: ("Connection broken: Connec ...