【洛谷 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 ...
随机推荐
- 团队作业7——第二次项目冲刺-Beta版本项目计划
上一个阶段的总结: 在Alpha阶段,我们小组已近完成了大部分的功能要求,小组的每一个成员都发挥了自己的用处.经过了这么久的磨合,小组的成员之间越来越默契,相信在接下来的合作中,我们的开发速度会越来越 ...
- js图片转换为base64
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- asp.netMVC中实现分页方法
方法一:使用传统的sql语句实现分页, public class UserprintDao如下 /// <summary> /// 取得用户申请记录列表(按分页) /// </ ...
- asp.net 间隔一段时间执行某方法
设想网站后台每秒自动更新一下Cache["test"]中的值,通过这个实现就可以完成一些在间隔多少时间更新一下数据库的操作. 1.定义一个事件类BMAEvent,在Processo ...
- 【bzoj2653】middle 可持久化线段树区间合并
题目描述 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[ ...
- Redis 基础:Redis 简介及安装
Remote Dictionary Server(Redis)是一个由Salvatore Sanfilippo写的key-value存储系统.Redis是一个开源的使用ANSI C语言编写.遵守BSD ...
- hdu 3191 How Many Paths Are There (次短路径数)
How Many Paths Are There Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java ...
- P1135 奇怪的电梯
题目描述 呵呵,有一天我做了一个梦,梦见了一种很奇怪的电梯.大楼的每一层楼都可以停电梯,而且第i层楼(1<=i<=N)上有一个数字Ki(0<=Ki<=N).电梯只有四个按钮:开 ...
- [CF452E]Three strings
题目大意:给你三个字符串$A,B,C$,令$L=min(|A|,|B|,|C|)$,对每个$i\in[1,L]$,求出符合$A_{[a,a+i)}=B_{[b,b+i)}=C_{[c,c+i)}$的三 ...
- 分享几款常用的API/文档浏览器
1.Dash 支持平台:Mac iOS 官网:https://kapeli.com/dash 2.Zeal 支持平台:Linux Windows 官网:https://zealdocs.org/ G ...