UVA 12307 Smallest Enclosing Rectangle(旋转卡壳)
题意:给你一些点,找出两个可以包含所有点的矩形,一个保证矩形面积最小,一个保证矩形周长最小,输出两个最小值
题解:首先根据所有点求一个凸包,再在这个凸包上枚举每条边,作为矩形的一条边(这样可以保证最小)
接着根据旋转卡壳的思想求出另外三条边,这样枚举判断就好
求另三条边时首先方向是确定了的,找点就是旋转卡壳,思想就是:枚举的任意两条边a与b,a的另三条边与b的另三条边都不会再a与b之间,并且b对应边一定最a对应边的 后面(注意是循环的边)那么就是说,我们可以使用类似双指针方式维护,但是时间复杂度却为O(n)
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #include<string> #include<cstdio> #include<cstring> #include<iomanip> #include<stdlib.h> #include<iostream> #include<algorithm> using namespace std; #define eps 1E-8 /*注意可能会有输出-0.000*/ #define sgn(x) (x<-eps? -1 :x<eps? 0:1)//x为两个浮点数差的比较,注意返回整型 #define cvs(x) (x > 0.0 ? x+eps : x-eps)//浮点数转化 #define zero(x) (((x)>0?(x):-(x))<eps)//判断是否等于0 #define mul(a,b) (a<<b) #define dir(a,b) (a>>b) typedef long long ll; typedef unsigned long long ull; const int Inf=1<<28; const ll INF=1LL<<60; const double Pi=acos(-1.0); const int Mod=1e9+7; const int Max=500010; struct Point {double x,y;Point(double x=0,double y=0):x(x),y(y) {};inline Point operator-(const Point& a)const{return Point(x-a.x,y-a.y);}inline bool operator<(const Point& a)const{return sgn(x-a.x)<0||zero(x-a.x)&&sgn(y-a.y)<0;}inline Point operator+(const Point& a)const{return Point(x+a.x,y+a.y);}inline bool operator!=(const Point& a)const{return !(zero(x-a.x)&&zero(y-a.y));} }; typedef Point Vector; struct Line {Point p;Vector v;double ang;//极角 Line() {};Line(Point p,Vector v):p(p),v(v){ang=atan2(v.y,v.x);}inline bool operator<(const Line& L)const{return ang<L.ang;} }; double Dis(Point A,Point B) {return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)); } double Cross(Vector A,Vector B) {return A.x*B.y-A.y*B.x; } int ConvexHull(Point *p,int n,Point *convex)//求凸包 {sort(p,p+n);int m=0;for(int i=0; i<n; ++i){while(m>1&&Cross(convex[m-1]-convex[m-2],p[i]-convex[m-2])<0){m--;}convex[m++]=p[i];}int k=m;for(int i=n-2; i>=0; --i){while(m>1&&Cross(convex[m-1]-convex[m-2],p[i]-convex[m-2])<0){m--;}convex[m++]=p[i];}if(n>1)m--;return m; } Point intersection(Point p1,Point p2,Point l1,Point l2)//交点坐标 {Point ret=p1;//首先计算直线是否平行double t=((p1.x-l1.x)*(l1.y-l2.y)-(p1.y-l1.y)*(l1.x-l2.x))/((p1.x-p2.x)*(l1.y-l2.y)-(p1.y-p2.y)*(l1.x-l2.x));ret.x+=(p2.x-p1.x)*t;ret.y+=(p2.y-p1.y)*t;return ret;//线段交点另外判断线段相交(同时判断是否平行) } Point now[Max],convex[Max]; double area,per; double GetArea(Line up,Line down,Line left,Line right)//根据矩形四条线求面积 {Point minx=intersection(left.p,left.p+left.v,down.p,down.p+down.v);Point miny=intersection(right.p,right.p+right.v,down.p,down.p+down.v);Point manx=intersection(left.p,left.p+left.v,up.p,up.p+up.v);return Dis(minx,manx)*Dis(minx,miny); } double GetPer(Line up,Line down,Line left,Line right) {Point minx=intersection(left.p,left.p+left.v,down.p,down.p+down.v);Point miny=intersection(right.p,right.p+right.v,down.p,down.p+down.v);Point manx=intersection(left.p,left.p+left.v,up.p,up.p+up.v);return (Dis(minx,manx)+Dis(minx,miny))*2; } Vector Rotate(Vector A,double rad) //向量A逆时针旋转rad { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); } void RotateStuck(int n)//旋转卡壳枚举矩形 {for(int i=0;i<n;++i){convex[i+n]=convex[i];convex[i+n+n]=convex[i];}area=per=Inf;Line up,down,left,right;//四条直线int i=0,j=0,k=0,l=0;//四条线的位置for(; i<n; ++i)//枚举上这条线,则可以确定其他 {up=Line(convex[i],convex[i+1]-convex[i]);//其他三条直线所在的点与上这条线成单峰函数k=max(i,k);//每次是逆时针旋转,保证是凸包上一条线或者后面的线while(Cross(Rotate(up.v,Pi/2),convex[k+1]-convex[k])<0)//通过旋转来判断k++;left=Line(convex[k],Rotate(up.v,Pi/2));j=max(k,j);while(Cross(Rotate(up.v,Pi),convex[j+1]-convex[j])<0)j++;down=Line(convex[j],Rotate(up.v,Pi));l=max(j,l);while(Cross(Rotate(up.v,3*Pi/2),convex[l+1]-convex[l])<0)l++;right=Line(convex[l],Rotate(up.v,3*Pi/2));area=min(area,GetArea(up,down,left,right));per=min(per,GetPer(up,down,left,right));}return ; } int main() {int n;while(~scanf("%d",&n)&&n){for(int i=0; i<n; ++i){scanf("%lf %lf",&now[i].x,&now[i].y);}int m= ConvexHull(now,n,convex);RotateStuck(m);printf("%.2f %.2f\n",area,per);}return 0; }
转载于:https://www.cnblogs.com/zhuanzhuruyi/p/6371875.html
UVA 12307 Smallest Enclosing Rectangle(旋转卡壳)相关推荐
- CF1578F Framing Pictures 旋转卡壳+积分
CF1578F Framing Pictures 旋转卡壳+积分 Framing Pictures 题目描述 Life has been discovered on Venus! What is mo ...
- 旋转卡壳算法求最小外接矩形代码
旋转卡壳原理:旋转卡壳详解_大学要有梦想的博客-CSDN博客_旋转卡壳 思路: 1.选择卡壳算法用于求凸多边形的最小外接矩形 1.多边形最小的外接矩形一定是以多边形的的一条边为底的一部分 2.通过这条 ...
- 算法复习——凸包加旋转卡壳(poj2187)
题目: Description Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest ...
- Bridge Across Islands POJ - 3608 旋转卡壳求凸包最近距离
\(\color{#0066ff}{题目描述}\) 几千年前,有一个小王国位于太平洋的中部.王国的领土由两个分离的岛屿组成.由于洋流的冲击,两个岛屿的形状都变成了凸多边形.王国的国王想建立一座桥来连接 ...
- BZOJ 1185: [HNOI2007]最小矩形覆盖 [旋转卡壳]
1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec Memory Limit: 162 MBSec Special Judge Submit: 1435 Solv ...
- 算法学习:计算几何旋转卡壳
[定义] [对踵点]多边形上存在平行切线的两点 [多边形半径]多边形上任意两点的最大长度 [旋转卡壳] 选取y轴上,最高和最低的两个点,令两条平行于x轴的线切过这两点 然后我们开始让这两条线旋转 当一 ...
- bzoj 1069 [SCOI2007]最大土地面积——旋转卡壳
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1069 发现 n 可以 n^2 .所以枚举对角线,分开的两部分三角形就可以旋转卡壳了. 注意坐 ...
- 【BZOJ1185】【HNOI2007】最小矩形覆盖(凸包+旋转卡壳)
传送门 题意:求最小矩阵覆盖 有这样一个结论:矩阵一定有一条边在凸包上(不会证) 那可以枚举每条边 同时旋转卡壳 只是这时不只维护一个对踵点对,同时在左右侧再维护一个最远点 可以发现左右最远点一定是和 ...
- poj 2079(旋转卡壳)
题意:求出平面内的点集所组成的面积最大的三角形. 解题思路:考虑凸包+旋转卡壳.面积最大的三角形的三点必定在凸包的顶点上,只不过这里要注意,三角形的边不一定就是凸包的边,有可能三角形相邻两点是横跨凸包 ...
- poj 2187 Beauty Contest (凸包: 最远点对,最长直径 , 旋转卡壳法)
http://poj.org/problem?id=2187 题意: 最长的点对近距离的平方: 题解: 旋转卡壳法, 要注意的地方是,有 所有点共线的情况,所以,(求凸包时)要将,共线点去出 : ...
最新文章
- 2021-08-09 图像灰度二值化
- 《调色师手册:电影和视频调色专业技法(第2版)》——调色师该何时介入?...
- linux 进程间通信 命名管道FIFO的原理与使用
- 多益网络 视频面试面试总结20180816
- T-SQL远程数据库备份还原
- python入门——P39类和对象:拾遗
- Unity 项目 - Ruby‘s Adventure 学习笔记
- php医院数据库设计,检查我的数据库设计/ PHP / MySQL
- 统计学习方法读书笔记3-感知机SVM
- 虚函数和虚析构函数的实现原理--虚函数表
- 对自己编译的文件(exe/dll)进行签名的实践(Windows)
- Oct.14 华为数通部算法岗面经
- powerdesign如何利用表导出sql
- Flutter 旋转动画
- opengl——贴图
- 捋一捋Python中的Dict(下)
- html5水墨背景,好看的水墨画背景图片
- 1.通过PADS Logic创建原件类型和逻辑封装
- Linux: 查看文件和文件夹大小的df和du命令
- 内部培训——规范原则与重构