【洛谷 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 ...
随机推荐
- LintCode-71.二叉树的锯齿形层次遍历
二叉树的锯齿形层次遍历 给出一棵二叉树,返回其节点值的锯齿形层次遍历(先从左往右,下一层再从右往左,层与层之间交替进行) 样例 给出一棵二叉树 {3,9,20,#,#,15,7}, 返回其锯齿形的层次 ...
- 手把手教你写Kafka Streams程序
本文从以下四个方面手把手教你写Kafka Streams程序: 一. 设置Maven项目 二. 编写第一个Streams应用程序:Pipe 三. 编写第二个Streams应用程序:Line Split ...
- KMP算法字符串查找子串
题目: 经典的KMP算法 分析: 和KMP算法对应的是BF算法,其中BF算法时间复杂度,最坏情况下可以达到O(n*m),而KMP算法的时间复杂度是O(n + m),所以,KMP算法效率高很多. 但是K ...
- [剑指Offer] 39.平衡二叉树
题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. class Solution { public: int Get_Height(TreeNode* root) { if(root == NU ...
- 【Python】从1<2<3的语法糖说起
python有一个很有意思的语法糖你可以直接写1<2<3. 这复合我们通常意义上的数学不等式,但对学过C等语言其实是有疑惑的. 我们知道不等式返回的其实是个Bool值,在C中是1,0因此C ...
- Flask的第一个应用
Flask 是一个 Python 实现的 Web 开发微框架,微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展. 与Django功能上比较: Django:中间件,路由系统,视图(CBV ...
- (五)Redis集合Set操作
Set全部命令如下: sadd key member1 member2 ... # 将一个或多个member元素加入到集合key中,已经存在于集合的member元素将被忽略 spop key # 移除 ...
- Elasticsearch 插件head和kibana
本次安装在win7下,linux操作差不多. Elasticsearch的版本是6.5.1 一.前置条件 1.安装nodejs,如果已经安装了,检查一下版本,最好大于6以上,不然后面会失败,官网上已经 ...
- Html CSS学习(五)position定位 原
Html CSS学习(五)position定位 position用来对元素进行定位,其值有以下几种: static:无特殊定位,对象遵循正常文档流,top,right,bottom,left等属性不会 ...
- POJ2318:TOYS——题解
http://poj.org/problem?id=2318 题目大意:给一个大矩形,分成n+1份,求落在每一份的点的数量. —————————————————— 首先叉积可以判断一个点在边界的左边还 ...