首页 > 代码库 > BZOJ 1185 HNOI2007 最小矩形覆盖 旋转卡壳

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;
}


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