P3187 [HNOI2007]最小矩形覆盖

题意

考虑矩形必定满足一条边和凸包重合(意会),于是我们枚举凸包的每一条边,考虑维护据该条边的最远点\(p\)、最左点\(l\)、最右点\(r\),这三个都可以旋转卡壳。

首先最远点是经典的求凸包直径问题,我们移动时比较当前和下一个三角形的大小即可。

之后考虑最左点和最右点,我们用点积求出投影长度来比较就好了。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
const double eps=1e-12;
const double inf=1e9;
int n,m;
double ans=inf;
struct Point
{
    double x,y;
    inline double len(){return sqrt(x*x+y*y);}
    Point operator+(const Point a)const{return (Point){x+a.x,y+a.y};}
    Point operator-(const Point a)const{return (Point){x-a.x,y-a.y};}
    Point operator*(const double k){return (Point){x*k,y*k};}
    Point operator/(const double k){return (Point){x/k,y/k};}
    double operator*(const Point a)const{return x*a.y-y*a.x;}
    double operator&(const Point a)const{return x*a.x+y*a.y;}
}p[maxn],sta[maxn],ansp[5];
inline int dcmp(double x)
{
	if(fabs(x)<=eps)return 0;
	return x<0?-1:1;
}
inline bool cmp1(Point a,Point b){return !dcmp(a.y-b.y)?dcmp(a.x-b.x)<0:dcmp(a.y-b.y)<0;}
inline bool cmp2(Point a,Point b)
{
	if(!dcmp(a.x)&&!dcmp(a.y))return 1;
	else if(!dcmp(b.x)&&!dcmp(b.y))return 0;
	else return atan2(a.y,a.x)<atan2(b.y,b.x);
}
inline Point get(Point a,Point b){return b-a;}
inline void build()
{
	sort(p+1,p+n+1,cmp1);
	for(int i=1;i<=n;i++)
	{
		while(m>1&&dcmp(get(sta[m-1],sta[m])*get(sta[m],p[i]))<=0)m--;
		sta[++m]=p[i];
	}
	int tmp=m;
	for(int i=n-1;i;i--)
	{
		while(m>tmp&&dcmp(get(sta[m-1],sta[m])*get(sta[m],p[i]))<=0)m--;
		sta[++m]=p[i];
	}
	m--;sta[0]=sta[m];
}
inline void solve()
{
	int l=1,r=1,p=1;
	double L=0,R=0,H=0;
	for(int i=0;i<m;i++)
	{
		while(dcmp(get(sta[i],sta[i+1])*get(sta[i],sta[p+1])-get(sta[i],sta[i+1])*get(sta[i],sta[p]))>=0)p=(p+1)%m;
		while(dcmp((get(sta[i],sta[i+1])&get(sta[i],sta[r+1]))-(get(sta[i],sta[i+1])&get(sta[i],sta[r]))>=0))r=(r+1)%m;
		if(!i)l=r;
		while(dcmp((get(sta[i],sta[i+1])&get(sta[i],sta[l+1]))-(get(sta[i],sta[i+1])&get(sta[i],sta[l]))<=0))l=(l+1)%m;
		double d=get(sta[i],sta[i+1]).len();
		L=(get(sta[i],sta[i+1])&get(sta[i],sta[l]))/d;
		R=(get(sta[i],sta[i+1])&get(sta[i],sta[r]))/d;
		H=fabs(get(sta[i],sta[i+1])*get(sta[i],sta[p])/d);
		double tmp=H*(R-L);
		if(tmp<ans)
		{
			ans=tmp;
			ansp[1]=sta[i]+get(sta[i],sta[i+1])*(R/d);
			ansp[2]=ansp[1]+get(ansp[1],sta[r])*(H/get(ansp[1],sta[r]).len());
			ansp[3]=ansp[2]+get(ansp[1],sta[i])*((R-L)/get(ansp[1],sta[i]).len());
			ansp[4]=ansp[1]+get(ansp[1],sta[i])*((R-L)/get(ansp[1],sta[i]).len());
		}
	}
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
	build();solve();
	printf("%.5lf\n",ans+eps);
	sort(ansp+1,ansp+4+1,cmp2);
	for(int i=1;i<=4;i++)printf("%.5lf %.5lf\n",ansp[i].x+eps,ansp[i].y+eps);
	return 0;
}
posted @ 2020-01-19 09:58  nofind  阅读(173)  评论(0编辑  收藏  举报