【洛谷 P3187】 [HNOI2007]最小矩形覆盖 (二维凸包,旋转卡壳)
题目链接
嗯,毒瘤题。
首先有一个结论,就是最小矩形一定有条边和凸包重合。脑补一下就好了。
然后枚举凸包的边,用旋转卡壳维护上顶点、左端点、右端点就好了。
上顶点用叉积,叉积越大三角形面积越大,对应的高也就越大。两边的点用点积,点积越大投影越大。
然后就是精度问题。这种实数计算最好不要直接用比较运算符,要用差和\(eps\)的关系来比较,我就是一直卡在这里。还好有爆炸\(OJ\)离线题库提供的数据。。。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 50010;
const double eps = 1e-8;
struct point{
double x, y;
inline double dis(){
return sqrt(x * x + y * y);
}
inline void print(){
if(fabs(x) < 1e-10) x = 0;
if(fabs(y) < 1e-10) y = 0;
printf("%.5lf %.5lf\n", x, y);
}
}p[MAXN];
inline double sig(double x){
return (x > eps) - (x < -eps);
}
int operator == (point a, point b){
return a.x == b.x && a.y == b.y;
}
point operator * (point a, double b){ // ba
return (point){ a.x * b, a.y * b };
}
double operator * (point a, point b){ // a x b
return a.x * b.y - b.x * a.y;
}
double operator / (point a, point b){ // a . b
return a.x * b.x + a.y * b.y;
}
point operator - (point a, point b){ // a - b
return (point){ a.x - b.x, a.y - b.y };
}
point operator + (point a, point b){ // a + b
return (point){ a.x + b.x, a.y + b.y };
}
int cmp(const point a, const point b){
return a.x == b.x ? a.y < b.y : a.x < b.x;
}
inline int judge(point a, point b, point c){ //Kab > Kac
return (b.y - a.y) * (c.x - a.x) > (c.y - a.y) * (b.x - a.x);
}
inline double mult(point a, point b, point c){
return (a - c) * (b - c);
}
inline double calc(point a, point b, point c){
return (b - a) / (c - a);
}
int n, top, tp;
point st[MAXN], ts[MAXN], Ans[5];
double ans = 1e18, d, a, b, L, R;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
sort(p + 1, p + n + 1, cmp);
for(int i = 1; i <= n; ++i){
if(p[i] == p[i - 1]) continue;
while(top > 1 && judge(st[top - 1], st[top], p[i])) --top;
st[++top] = p[i];
}
for(int i = 1; i <= n; ++i){
if(p[i] == p[i - 1]) continue;
while(tp > 1 && !judge(ts[tp - 1], ts[tp], p[i])) --tp;
ts[++tp] = p[i];
}
for(int i = tp - 1; i; --i) st[++top] = ts[i];
--top;
int j = 2, k = 2, l = 2;
for(int i = 1; i <= top; ++i){
while(sig(mult(st[i], st[i + 1], st[j]) - mult(st[i], st[i + 1], st[j + 1])) <= 0) if(++j > top) j = 1;
while(sig(calc(st[i], st[i + 1], st[k]) - calc(st[i], st[i + 1], st[k + 1])) <= 0) if(++k > top) k = 1;
if(i == 1) l = k;
while(sig(calc(st[i], st[i + 1], st[l]) - calc(st[i], st[i + 1], st[l + 1])) >= 0) if(++l > top) l = 1;
d = (st[i] - st[i + 1]).dis();
R = calc(st[i], st[i + 1], st[k]) / d;
L = calc(st[i], st[i + 1], st[l]) / d;
b = fabs(mult(st[i], st[i + 1], st[j]) / d);
a = R - L;
if(a * b < ans){
ans = a * b;
Ans[1] = st[i] + (st[i + 1] - st[i]) * (R / d);
Ans[2] = Ans[1] + (st[k] - Ans[1]) * (b / (st[k] - Ans[1]).dis());
Ans[3] = Ans[2] + (st[i] - Ans[1]) * (a / R);
Ans[4] = Ans[3] + (Ans[1] - Ans[2]);
}
}
printf("%.5lf\n", ans);
double Min = 1e18, pos;
for(int i = 1; i <= 4; ++i)
if(Ans[i].y < Min)
Min = Ans[i].y, pos = i;
for(int i = pos; i <= 4; ++i)
Ans[i].print();
for(int i = 1; i < pos; ++i)
Ans[i].print();
return 0;
}
【洛谷 P3187】 [HNOI2007]最小矩形覆盖 (二维凸包,旋转卡壳)的更多相关文章
- HDU 5251 矩形面积(二维凸包旋转卡壳最小矩形覆盖问题) --2015年百度之星程序设计大赛 - 初赛(1)
题目链接 题意:给出n个矩形,求能覆盖所有矩形的最小的矩形的面积. 题解:对所有点求凸包,然后旋转卡壳,对没一条边求该边的最左最右和最上的三个点. 利用叉积面积求高,利用点积的性质求最左右点和长度 ...
- poj 2079 Triangle (二维凸包旋转卡壳)
Triangle Time Limit: 3000MS Memory Limit: 30000KB 64bit IO Format: %I64d & %I64u Submit Stat ...
- poj 2187 Beauty Contest(二维凸包旋转卡壳)
D - Beauty Contest Time Limit:3000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u ...
- 【洛谷 P2742】【模板】二维凸包
题目链接 二维凸包板子..有时间会补总结的. #include <cstdio> #include <cmath> #include <algorithm> usi ...
- P3187 [HNOI2007]最小矩形覆盖
传送门 首先这个矩形的一条边肯定在凸包上.那么可以求出凸包然后枚举边,用类似旋转卡壳的方法求出另外三条边的位置,也就是求出以它为底最上面最右边最左边的点的位置.离它最远的点可以用叉积求,最左最右的可以 ...
- 【洛谷 P1452】 Beauty Contest (二维凸包,旋转卡壳)
题目链接 旋转卡壳模板题把. 有时间再补总结吧. #include <cstdio> #include <cmath> #include <algorithm> u ...
- 洛谷 P3187 BZOJ 1185 [HNOI2007]最小矩形覆盖 (旋转卡壳)
题目链接: 洛谷 P3187 [HNOI2007]最小矩形覆盖 BZOJ 1185: [HNOI2007]最小矩形覆盖 Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, ...
- 【BZOJ1185】[HNOI2007]最小矩形覆盖(凸包,旋转卡壳)
[BZOJ1185][HNOI2007]最小矩形覆盖(凸包,旋转卡壳) 题面 BZOJ 洛谷 题解 最小的矩形一定存在一条边在凸包上,那么枚举这条边,我们还差三个点,即距离当前边的最远点,以及做这条边 ...
- 1185: [HNOI2007]最小矩形覆盖
1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 1426 Solve ...
- 【旋转卡壳+凸包】BZOJ1185:[HNOI2007]最小矩形覆盖
1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec Memory Limit: 162 MBSec Special JudgeSubmit: 1945 Solve ...
随机推荐
- ubuntu中下载sublime相关问题
1.SublimeText3的安装 在网上搜索了一些ubuntu下关于sublime-text-3安装的方法,在这里针对自己尝试的情况进行反馈: 方法一(未成功): 在终端输入以下代码: sudo a ...
- MHDD工具使用简写
检查硬盘,建议接主板一口,DOS工具箱输入mhdd回车进入界面 输入硬盘接口号(这里不固定) 按F4是进行硬盘扫描,按两次就开始,按方向键进行快进 Mhdd界面输入 erase命令:擦除指定扇区范围内 ...
- 给MySQL字段添加索引的操作
1.添加PRIMARY KEY(主键索引): ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` ) 2.添加UNIQUE(唯一索引) : ALTE ...
- 初入py
1.下载工具sublime 我的网盘下载地址:https://pan.baidu.com/s/18-U1ZSg_zHoSAqUuvXj_PQ 直接解压即可 2.配置py27 在新建的文件里面编辑并保存 ...
- byte字节的输入流 建议使用字节数组形式接受内容 因为当输入流是汉字时候 会超出字节的范围 出现无法读取的现象
byte字节的输入流 建议使用字节数组形式接受内容 因为当输入流是汉字时候 会超出字节的范围 出现无法读取的现象
- BZOJ4850/BZOJ2216 JSOI2016灯塔/Poi2011Lightning Conductor(决策单调性)
即对每个i最大化hj-hi+sqrt(|i-j|).先把绝对值去掉,正反各做一次即可.注意到当x>y时,sqrt(x+1)-sqrt(x)<sqrt(y+1)-sqrt(y),所以若对于i ...
- [洛谷P4035][JSOI2008]球形空间产生器
题目大意:给你$n$个点坐标,要你求出圆心 题解:随机化,可以随机一个点当圆心,然后和每个点比较,求出平均距离$r$,如果到这个点的距离大于$r$,说明离这个点远了,就给圆心施加一个向这个点的力:若小 ...
- 【BZOJ2648】SJY摆棋子(KD-Tree)
[BZOJ2648]SJY摆棋子(KD-Tree) 题面 BZOJ Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一 ...
- 【神仙DP】【UVa11400】Lighting System Design
传送门 Description Translation 题目大意:有一个照明系统需要用到n种灯,每种灯的电压为V,电源费用K,每个灯泡费用为C,需要该灯的数量为L.注意到,电压相同的灯泡只需要共享一个 ...
- Install JDK In Ubuntu
安装Linux软件包管理器rpm apt install rpm 查看已安装的软件,如JDK rpm -qa|grep jdk #查询所有 找jdk 卸载已安装的软件 rpm -e nodeps 包名 ...