BZOJ 1185 HNOI2007 最小矩形覆盖 旋转卡壳

题目大意:最小矩形覆盖

首先有一个结论:凸包上一定有一条边与矩形的一条边重合

证明:如果不存在一条边与矩形的一条边重合,那么我将这个矩形旋转一下一定会比之前更小

于是我们枚举其中一条边,对其余三个点卡壳即可

这旋转卡壳写的真叫一个卡壳- - 还好1A掉了- -

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
#define EPS 1e-7
using namespace std;
struct Point{
	double x,y;
	Point() {}
	Point(double _,double __):
		x(_),y(__) {}
	friend istream& operator >> (istream &_,Point &p)
	{
		scanf("%lf%lf",&p.x,&p.y);
		return _;
	}
	bool operator < (const Point &p) const
	{
		if(fabs(x-p.x)<EPS)
			return y<p.y;
		return x<p.x;
	}
	Point operator + (const Point &p) const
	{
		return Point(x+p.x,y+p.y);
	}
	Point operator - (const Point &p) const
	{
		return Point(x-p.x,y-p.y);
	}
	double operator * (const Point &p) const
	{
		return x*p.y-y*p.x;
	}
	Point operator * (const double &rate) const
	{
		return Point(x*rate,y*rate);
	}
	friend ostream& operator << (ostream& _,const Point &p)
	{
		printf("%.5lf %.5lf",p.x,p.y);
		return _;
	}
}points[M];
struct Line{
	Point p,v;
	Line() {}
	Line(const Point &_,const Point &__):
		p(_),v(__) {}
};
int n,top;
double ans=1e15;
Point ans_points[4];
Point *stack[M<<1];
Point Get_Intersection(const Line &l1,const Line &l2)
{
	Point u=l1.p-l2.p;
	double temp=(l2.v*u)/(l1.v*l2.v);
	return l1.p+l1.v*temp;
}
void Get_Convex_Hull()
{
	static Point *stack[M];
	int i,top=0;
	for(i=1;i<=n;i++)
	{
		while( top>=2 && (*stack[top]-*stack[top-1])*(points[i]-*stack[top])>=-EPS )
			stack[top--]=0x0;
		stack[++top]=&points[i];
	}
	for(i=1;i<=top;i++)
		::stack[++::top]=stack[i];
	top=0;
	for(i=1;i<=n;i++)
	{
		while( top>=2 && (*stack[top]-*stack[top-1])*(points[i]-*stack[top])<=EPS )
			stack[top--]=0x0;
		stack[++top]=&points[i];
	}
	for(i=top-1;i>1;i--)
		::stack[++::top]=stack[i];
	int limit=::top;
	for(i=1;i<=limit;i++)
		::stack[++::top]=::stack[i];
	::stack[++::top]=::stack[1];
}
void Rotating_Calipers()
{
	int limit=top>>1;
	Point **p1,**p2,**p3,**p4;
	p1=stack+1;
	Point v1=(**(p1+1)-**p1);
	Point v2(v1.y,-v1.x);
	Point v3(v2.y,-v2.x);
	Point v4(v3.y,-v3.x);
	for(p2=p1;(**(p2+1)-**p2)*v2<0;p2++);
	for(p3=p2;(**(p3+1)-**p3)*v3<0;p3++);
	for(p4=p3;(**(p4+1)-**p4)*v4<0;p4++);
	for(;p1<=stack+limit;p1++)
	{
		v1=(**(p1+1)-**p1);
		v2=Point(v1.y,-v1.x);
		v3=Point(v2.y,-v2.x);
		v4=Point(v3.y,-v3.x);
		for(;(**(p2+1)-**p2)*v2<0;p2++);
		for(;(**(p3+1)-**p3)*v3<0;p3++);
		for(;(**(p4+1)-**p4)*v4<0;p4++);

		Point temp_points[4];
		Line l1(**p1,v1);
		Line l2(**p2,v2);
		Line l3(**p3,v3);
		Line l4(**p4,v4);
		temp_points[0]=Get_Intersection(l1,l4);
		temp_points[1]=Get_Intersection(l4,l3);
		temp_points[2]=Get_Intersection(l3,l2);
		temp_points[3]=Get_Intersection(l2,l1);
		double area=(temp_points[1]-temp_points[0])*(temp_points[3]-temp_points[0]);
		if(area<ans)
			memcpy(ans_points,temp_points,sizeof ans_points),ans=area;
	}
}
int main()
{
	int i;
	cin>>n;
	for(i=1;i<=n;i++)
		cin>>points[i];
	sort(points+1,points+n+1);
	Get_Convex_Hull();
	Rotating_Calipers();
	printf("%.5lf\n",ans);
	int st=0;
	for(i=1;i<4;i++)
		if( ans_points[i].y<ans_points[st].y ||
			fabs(ans_points[i].y-ans_points[st].y)<EPS && ans_points[i].x<ans_points[st].x )
			st=i;
	for(i=0;i<4;i++)
		cout<<ans_points[i+st&3]<<endl;
	return 0;
}
时间: 2024-11-08 21:46:23

BZOJ 1185 HNOI2007 最小矩形覆盖 旋转卡壳的相关文章

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

[HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 2081  Solved: 920[Submit][Status][Discuss] Description 给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形, 输出所求矩形的面积和四个顶点坐标 Input 第一行为一个整数n(3<=n<=50000) 从第2至第n+1行每行有两个浮点数,表示一个顶点的x和y坐标,不用科学计

BZOJ 1185 [HNOI2007]最小矩形覆盖:凸包 + 旋转卡壳

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1185 题意: 给出二维平面上的n个点,问你将所有点覆盖的最小矩形面积. 题解: 先找出凸包,然后旋转卡壳. 在旋转卡壳中有一个结论:最小覆盖矩形一定有一条边在凸包上. 所以先枚举矩形在凸包上的那条边(p[i],p[i+1]),然后利用单调性找出p[i]的对踵点p[u]. 至于左右两侧的切点p[l]和p[r],要利用它们连线在直线(p[i],p[i+1])上投影长度的单调性求出. 最后将

1185: [HNOI2007]最小矩形覆盖

1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1426  Solved: 648[Submit][Status][Discuss] Description Input Output Sample Input Sample Output HINT Source 计算几何 vfleaking提供Spj #include<cstdio> #include<cmat

BZOJ 1185 HNOI 2007 最小矩形覆盖 旋转卡壳

题目大意:给出平面上的一些点,问面积最小的矩形满足覆盖所有的点. 思路:覆盖问题和不是凸包上的点没关系,先做凸包.根据贪心的思想,这个覆盖了所有点的矩形肯定至少有一条边与凸包上的边重合,那么我们枚举凸包上的每一条边,对于这个已经确定了一条边的矩形,不难确定其他三个边.注意到已知当前直线的向量,就可以求出两侧和对面的向量,而这三个向量随着枚举的边的移动是单调的,所以就可以用旋转卡壳来卡住剩下的三条边. 但是旋转卡壳时的初值会出问题,如果按照逆时针的顺序求出剩下的三条边的时候,要想通过向量直接卡第三

【bzoj_1185】[HNOI2007]最小矩形覆盖

咳咳..这会来总结一下1185的解题思路(这么一道破题调了一整天我会乱说? 首先做凸包,这个谁都知道我就不说了 然后问题转化为了凸多边形的最小矩形覆盖 有一个结论是 一个凸包的最小矩形覆盖一定有矩形的一条边在凸包上 请注意是结论..不是猜想.这个结论的正确性嘛..wys神犇给出的解释是这样的 好吧.. 然后我们可以以逆时针的顺序枚举每条边,作为矩形的一条边所在的直线.显然,矩形与这条边平行的边一定过这条边的对踵点.这一步骤旋转卡壳就可以在均摊O(1)的时间下完成. 然后问题来了,如何在快速找到最

BZOJ1185: [HNOI2007]最小矩形覆盖

传送门 旋转卡壳. 首先求凸包没什么好商量的. 然后有一个结论,如果存在一个最小的矩形覆盖,那么凸包里必定存在一条边和矩形的边重合. 自己yy一下就好啦,很容易想明白. 然后枚举每条边,移动另外三条边即可. 注意点积,叉积的结合运用什么的. //BZOJ 1185 //by Cydiater //2017.1.29 #include <iostream> #include <map> #include <ctime> #include <cmath> #in

bzoj1185【HNOI2007】最小矩形覆盖

1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge Submit: 1114  Solved: 505 [Submit][Status][Discuss] Description 凸包+旋转卡壳 首先有一个结论:矩形一定有一条边在凸包上,否则我们旋转之后一定会得到一个更小的矩形,脑补一下. 然后枚举凸包上的边,用旋转卡壳维护矩形的另外三条边,同时更新答案即可. #include<ios

bzoj 1185 旋转卡壳 最小矩形覆盖

题目大意 就是求一个最小矩形覆盖,逆时针输出其上面的点 这里可以看出,那个最小的矩形覆盖必然有一条边经过其中凸包上的两个点,另外三条边必然至少经过其中一个点,而这样的每一个点逆时针走一遍都满足单调性 所以可以利用旋转卡壳的思想找到这样的三个点 以每一条边作为基础,循环n次得到n个这样的矩形,找到其中面积最小的即可 然后自己画画图,作出矩形对应的两条边的单位向量,那么这四个点就非常好求了 1 #include <iostream> 2 #include <cstdio> 3 #inc

HDU 5251 矩形面积(二维凸包旋转卡壳最小矩形覆盖问题) --2015百度之星题目

B - 矩形面积 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description 小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少. Input 第一行一个正整数 T,代表测试数据组数(),接下来 T 组测试数据. 每组测试数据占若干行,第一行一个正整数 ,代表矩形的数量.接下来 N 行,每行 8