【BZOJ1185】[HNOI2007]最小矩形覆盖(凸包,旋转卡壳)

题面

BZOJ

洛谷

题解

最小的矩形一定存在一条边在凸包上,那么枚举这条边,我们还差三个点,即距离当前边的最远点,以及做这条边的垂线的最靠左和最靠右的两个点。

最远点很容易求,叉积计算面积来比就好了。

那么剩下两个点呢?

比如说找右侧的那个点,我们假装当前枚举出来的这条边就是水平线,那么只要当前的点和下一个点的直线与\(x\)轴正半轴夹角小于\(90°\) 显然就往这个方向走。然后从水平线换到一般的情况,也就是和枚举的这条边的夹角小于\(\frac{\pi}{2}\),点积的计算除了坐标计算之外,还有\(\vec{a}\dot{}\vec{b}=|\vec{a}|*|\vec{b}|*cos<\vec{a},\vec{b}>\),这样子可以很容易求出两个向量之间的夹角关系,而\(\alpha\le \frac{\pi}{2}\)换成三角函数之间的关系就是\(cos\alpha\ge 0\),因此找这个关系只需要很简单的判断两个向量之间的点积是否大于等于\(0\)。

同理,考虑如何找最靠左的点,那么就是两个向量的夹角范围在\(\frac{\pi}{2}\)以上,即点积小于\(0\)。

通过这个方法,似乎可以求解已知所有夹角的\(n\)边形覆盖,只需要旋转卡壳的时候依次考虑每个点,而每个点是否能否移动到下个点的条件与夹角相关,而夹角的信息可以通过点积得到。

然后这题就是卡精度卡精度卡精度之类的

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define double long double
#define MAX 50050
const double eps=1e-10;
const double Pi=acos(-1);
struct Point{double x,y,ang;};
bool operator<(Point a,Point b){return (a.ang!=b.ang)?a.ang<b.ang:a.x<b.x;}
Point operator+(Point a,Point b){return (Point){a.x+b.x,a.y+b.y};}
Point operator-(Point a,Point b){return (Point){a.x-b.x,a.y-b.y};}
Point operator*(Point a,double b){return (Point){a.x*b,a.y*b};}
Point operator/(Point a,double b){return (Point){a.x/b,a.y/b};}
double operator*(Point a,Point b){return a.x*b.x+a.y*b.y;}
double Cross(Point a,Point b){return a.x*b.y-a.y*b.x;}
double Len(Point a){return sqrt(a.x*a.x+a.y*a.y);}
double Dis(Point a,Point b){return Len(a-b);}
Point Rotate(Point p,double a){double c=cos(a),s=sin(a);return (Point){p.x*c-p.y*s,p.x*s+p.y*c};}
Point S[MAX],Ans[10];int top;
void Graham(Point *p,int n)
{
int pos=1;
for(int i=2;i<=n;++i)
if(p[i].x<p[pos].x||(p[i].x==p[pos].x&&p[i].y<p[pos].y))
pos=i;
swap(p[1],p[pos]);
for(int i=2;i<=n;++i)p[i].ang=atan2(p[i].y-p[1].y,p[i].x-p[1].x);
sort(&p[2],&p[n+1]);S[++top]=p[1];S[++top]=p[2];
for(int i=3;i<=n;++i)
{
while(top>2&&Cross(p[i]-S[top],p[i]-S[top-1])>=0)--top;
S[++top]=p[i];
}
}
struct Line{Point a,v;};
Point Intersection(Line a,Line b)
{
Point c=b.a-a.a;
double t=Cross(b.v,c)/Cross(b.v,a.v);
return a.a+a.v*t;
}
int n;double ans=1e18;
Point p[MAX],tmp[5];
void ScanLine(int n)
{
S[n+1]=S[1];S[0]=S[n];
for(int i=1,j1=3,j2=3,j3=n;i<=n;++i)
{
if(i==1)while((S[i]-S[i+1])*(S[j3-1]-S[j3])>0)j3=(j3==1)?n:j3-1;
while(Cross(S[j1]-S[i],S[j1]-S[i+1])<=Cross(S[j1+1]-S[i],S[j1+1]-S[i+1]))j1=(j1==n)?1:j1+1;
while((S[i+1]-S[i])*(S[j2+1]-S[j2])>0)j2=(j2==n)?1:j2+1;
while((S[i+1]-S[i])*(S[j3+1]-S[j3])<0)j3=(j3==n)?1:j3+1;
Line l0=(Line){S[i],S[i+1]-S[i]};
Line l1=(Line){S[j1],S[i]-S[i+1]};
Line l2=(Line){S[j2],Rotate(S[i+1]-S[i],Pi/2)};
Line l3=(Line){S[j3],Rotate(S[i]-S[i+1],Pi/2)};
tmp[1]=Intersection(l0,l2);
tmp[2]=Intersection(l2,l1);
tmp[3]=Intersection(l1,l3);
tmp[4]=Intersection(l3,l0);
double area=Dis(tmp[1],tmp[2])*Dis(tmp[2],tmp[3]);
if(area<ans)
ans=area,Ans[1]=tmp[1],Ans[2]=tmp[2],Ans[3]=tmp[3],Ans[4]=tmp[4];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%Lf%Lf",&p[i].x,&p[i].y);
for(int i=1;i<=n;++i)p[i].x+=eps,p[i].y-=eps;
Graham(p,n);
ScanLine(top);
printf("%.5Lf\n",ans);
Ans[5]=Ans[1];Ans[6]=Ans[2];Ans[7]=Ans[3];Ans[8]=Ans[4];
int pos=1;
for(int i=2;i<=4;++i)
if(Ans[i].y<Ans[pos].y||(Ans[i].y==Ans[pos].y&&Ans[i].x<=Ans[pos].x))
pos=i;
for(int i=pos;i<=pos+3;++i)printf("%.5Lf %.5Lf\n",Ans[i].x+100*eps,Ans[i].y+100*eps);
return 0;
}

【BZOJ1185】[HNOI2007]最小矩形覆盖(凸包,旋转卡壳)的更多相关文章

  1. [BZOJ1185][HNOI2007]最小矩形覆盖-[凸包+旋转卡壳]

    Description 传送门 Solution 感性理解一下,最小矩形一定是由一条边和凸包上的边重合的. 然后它就是模板题了..然而真的好难调,小于大于动不动就打错. Code #include&l ...

  2. BZOJ1185[HNOI2007] 最小矩形覆盖(旋转卡壳)

    BZOJ1185[HNOI2007] 最小矩形覆盖 题面 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,输出所求矩形的面积和四个顶点的坐标 分析 首先可以先求凸包,因为覆盖了凸包上的顶点,凸 ...

  3. BZOJ1185 [HNOI2007]最小矩形覆盖 【旋转卡壳】

    题目链接 BZOJ1185 题解 最小矩形一定有一条边在凸包上,枚举这条边,然后旋转卡壳维护另外三个端点即可 计算几何细节极多 维护另外三个端点尽量不在这条边上,意味着左端点尽量靠后,右端点尽量靠前, ...

  4. bzoj 1185 [HNOI2007]最小矩形覆盖 凸包+旋转卡壳

    题目大意 用最小矩形覆盖平面上所有的点 分析 有一结论:最小矩形中有一条边在凸包的边上,不然可以旋转一个角度让面积变小 简略证明 我们逆时针枚举一条边 用旋转卡壳维护此时最左,最右,最上的点 注意 注 ...

  5. 2018.10.18 bzoj1185: [HNOI2007]最小矩形覆盖(旋转卡壳)

    传送门 不难看出最后的矩形一定有一条边与凸包某条边重合. 因此先求出凸包,然后旋转卡壳求出当前最小矩形面积更新答案. 代码: #include<bits/stdc++.h> #define ...

  6. [HNOI2007][BZOJ1185] 最小矩形覆盖 [凸包+旋转卡壳]

    题面 BZOJ题面 前置芝士 建议先学习向量相关的计算几何基础 计算几何基础戳这里 思路 用这道题学习一下凸包和旋转卡壳 首先是凸包部分 凸包 求凸包用的算法是graham算法 算法流程如下: 找到$ ...

  7. BZOJ1185 HNOI2007 最小矩形覆盖 凸包、旋转卡壳

    传送门 首先,肯定只有凸包上的点会限制这个矩形,所以建立凸包. 然后可以知道,矩形上一定有一条边与凸包上的边重合,否则可以转一下使得它重合,答案会更小. 于是沿着凸包枚举这一条边,通过旋转卡壳找到离这 ...

  8. bzoj1185 [HNOI2007]最小矩形覆盖 旋转卡壳求凸包

    [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 2081  Solved: 920 ...

  9. BZOJ1185 : [HNOI2007]最小矩形覆盖

    求出凸包后,矩形的一条边一定与凸包的某条边重合. 枚举每条边,求出离它最远的点和离它最左最右的点,因为那三个点是单调变化的,所以复杂度为$O(n)$. 注意精度. #include<cstdio ...

  10. bzoj千题计划209:bzoj1185: [HNOI2007]最小矩形覆盖

    http://www.lydsy.com/JudgeOnline/problem.php?id=1185 题解去看它 http://www.cnblogs.com/TheRoadToTheGold/p ...

随机推荐

  1. Git push提交时报错Permission denied(publickey)...Please make sure you have the correct access rights and the repository exists.

    一.git push origin master 时出错 错误信息为: Permission denied(publickey). fatal: Could not read from remote ...

  2. windows 环境下 eclipse + maven + tomcat 的 hello world 创建和部署

    主要记录自己一个新手用 eclipse + maven + tomcat 搭建 hello world 的过程,以及遇到的问题.讲真都是自己通过百度和谷歌一步步搭建的项目,没问过高手,也没高手可问,由 ...

  3. babel (二) update to v7

    一.rootmode In 7.1, we've introduced a rootMode option for further lookup if necessary. 二.Remove prop ...

  4. python爬虫scrapy之rules的基本使用

    Link Extractors Link Extractors 是那些目的仅仅是从网页(scrapy.http.Response 对象)中抽取最终将会被follow链接的对象。 Scrapy默认提供2 ...

  5. Mybaits整合Spring

    整合思路 1.SqlSessionFactory对象应该放到spring容器中作为单例存在. 2.传统dao的开发方式中,应该从spring容器中获得sqlsession对象. 3.Mapper代理形 ...

  6. 原 线程池中shutdown()和shutdownNow()方法的区别

    参考:shutdown和shutdownNow的区别 shutDown() 当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态.此时,则不能再往线程池中添加任何任务,否则将会抛出Reje ...

  7. dede:field name=’position’标签调用 主页改成英文Home和改变符号

    在用dede:field name=’position’ 这个标签的时候我们调用的这个就是中文的,出现的是主页>+相应的栏目  ,那么这个问题怎么改成英文的呢?有好多大虾都说找到dede安装目录 ...

  8. Fiddler 学习笔记---命令、断点

    输入命令框: 1 输入 ?51testing  高亮显示对应记录 2 >10 选择body大于10的记录 3 <10 选择body<10的记录 4 =200 选择result=200 ...

  9. 取得数据表中前N条记录,某列重复的话只取第一条记录

    项目需要筛选出不重复数据,以前没有做过,第一反应就是利用distinct处理,但是弄了好久也没搞出来,大家有知道的望告知下. 这次筛选没有使用distinct ,是利用group by ,利用id为唯 ...

  10. 学习 Spring (十) 注解之 @Bean, @ImportResource, @Value

    Spring入门篇 学习笔记 @Bean @Bean 标识一个用于配置和初始化一个由 Spring IoC 容器管理的新对象的方法,类似于 XML 配置文件的 可以在 Spring 的 @Config ...