【洛谷 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 ...
随机推荐
- pfx 证书怎么打开
其实双击就能够自动运行导入向导的 不行的话使用我的办法: 单击开始--运行--里输入mmc 然后单击文件--选择添加删除管理单元--再选择添加--拉动滚动条找到证书一项,点击添加再点击完成(不用做任何 ...
- iframe 随内容自适应高度
兼容性好的 html代码: <iframe src="enterprise/enter_edit.aspx" id="mainframe" framebo ...
- Java-编译后出现$1.class、$2.class等多个class文件
部署代码的时候,由于自身技术不精和疏忽,导致查询数据没有正常显示, 排除法最后只能是放置部署文件时未包括多出来的$class文件.放上去之后果然好使了,才记录下这个问题... 这是因为在我们写的类中存 ...
- phpcms V9如何判断用户是否登录以及登陆后的标签写法问题
首先要获取userid {php$userid=param::get_cookie('_userid');} 然后再判断是否为空 {if $userid}...这里写已经登录之后的代码...{els ...
- 利用Fiddler,解密wireshark抓的HTTPS包
背景介绍 HTTPS加密方式介绍 浏览器-->SSL Client Hello(我支持这些加密方式)-->服务器 浏览器<-SLL Server Hello(就用这种加密,然后下面是 ...
- windows下apache+php安装
1.安装apache 通过exe安装,如果80端口被占用,修改httpd.conf中的Listen,然后再次用exe安装,选择repaire 2.安装php 解压php包,添加系统变量 path,加上 ...
- [socket编程] 一个服务器与多个客户端之间通信
转自:http://blog.csdn.net/neicole/article/details/7539444 并加以改进 Server程序: // OneServerMain.cpp #includ ...
- [BZOJ4589]Hard Nim
description BZOJ 题意:\(n\)堆式子,每堆石子数量为\(\le m\)的质数,对于每一个局面玩\(Nim\)游戏,求后手必胜的方案数. data range \[n\le 10^9 ...
- Jquery常用正则验证
常用校验的正则表达式var rulesConfig = { /** * str.replace(/^\s+|\s+$/g, '') 解析: str:要替换的字符串 \s : 表示 space ,空格 ...
- UVA.11464 Even Parity (思维题 开关问题)
UVA.11464 Even Parity (思维题 开关问题) 题目大意 给出一个n*n的01方格,现在要求将其中的一些0转换为1,使得每个方格的上下左右格子的数字和为偶数(如果存在的话),求使得最 ...