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

传送门

题意:求最小矩阵覆盖

有这样一个结论:矩阵一定有一条边在凸包上(不会证)

那可以枚举每条边
同时旋转卡壳
只是这时不只维护一个对踵点对,同时在左右侧再维护一个最远点
可以发现左右最远点一定是和当前边点积最小/最大的
不断统计答案就是了

注意printfprintf遇到0.0000.000会输出0.0000-0.0000,要特判一下

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char ch=getchar();
	int res=0,f=1;
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
	return res*f;
}
const int N=50005;
const double pi=acos(-1);
const double eps=1e-8;
struct point{
	double x,y;
	point(double a=0,double b=0){
		x=a,y=b;
	}
	friend inline point operator +(const point &a,const point &b){
		return point(a.x+b.x,a.y+b.y);
	}
	friend inline point operator -(const point &a,const point &b){
		return point(a.x-b.x,a.y-b.y);
	}
	friend inline double operator *(const point &a,const point &b){
		return (a.x*b.y-a.y*b.x);
	}
	friend inline point operator *(const point &a,const double &b){
		return point(a.x*b,a.y*b);
	}
	friend inline double operator /(const point &a,const point &b){
		return a.x*b.x+a.y*b.y;
	}
	inline double calc(){
		return sqrt(x*x+y*y);
	}
}p[N],q[N],t[5];
inline bool comp(const point &a,const point &b){
	double res=(a-p[1])*(b-p[1]);
	return (res==0)?((a-p[1]).calc()<(b-p[1]).calc()):(res>0);
}
int n,top;
double ans=1e9;
inline void graham(){
	int idx=1;
	for(int i=2;i<=n;i++){
		if(p[idx].y>p[i].y||(p[idx].y==p[i].y&&p[i].x<p[idx].x))
		idx=i;
	}
	if(idx!=1)swap(p[idx],p[1]);
	sort(p+2,p+n+1,comp);
	q[++top]=p[1];
	for(int i=2;i<=n;++i){
		while(top>=3&&((p[i]-q[top-1])*(q[top]-q[top-1])>=0))
			top--;
		q[++top]=p[i];
	}
	q[0]=q[top];
}
inline void solve(){
	int l=1,r=1,h=1;
	for(int i=0;i<top;i++){
		double dis=(q[i]-q[i+1]).calc();
		while((q[i+1]-q[i])*(q[h+1]-q[i])-(q[i+1]-q[i])*(q[h]-q[i])>-eps)h=(h+1)%top;
		while((q[i+1]-q[i])/(q[r+1]-q[i])-(q[i+1]-q[i])/(q[r]-q[i])>-eps)r=(r+1)%top;
		if(i==0)l=r;
		while((q[i+1]-q[i])/(q[l+1]-q[i])-(q[i+1]-q[i])/(q[l]-q[i])<eps)l=(l+1)%top;
	    double lg=(q[i+1]-q[i])/(q[l]-q[i])/dis,rg=(q[i+1]-q[i])/(q[r]-q[i])/dis;
		double ht=(q[i+1]-q[i])*(q[h]-q[i])/dis;
		if(ht<0)ht=-ht;
		if((rg-lg)*ht<ans){
			ans=(rg-lg)*ht;
			t[0]=q[i]+(q[i+1]-q[i])*(rg/dis);
			t[1]=t[0]+(q[r]-t[0])*(ht/(q[r]-t[0]).calc());
			t[2]=t[1]+(q[i]-t[0])*((rg-lg)/(q[i]-t[0]).calc());
			t[3]=t[2]+(t[0]-t[1]);
		}
	}
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%lf%lf",&p[i].x,&p[i].y);
	}
	graham();
	solve();
	if(ans<eps)cout<<"0.00000\n";
	else printf("%.5lf\n",ans);
	int d=0;
	for(int i=1;i<=3;i++){
		if(t[i].y<t[d].y||(t[i].y==t[d].y&&t[i].x<t[d].x))
		d=i;
	}
	for(int i=0;i<=3;i++){
		if(t[(i+d)%4].x<eps)cout<<"0.00000 ";
		else printf("%.5lf ",t[(i+d)%4].x);
		if(t[(i+d)%4].y<eps)cout<<"0.00000\n";
		else printf("%.5lf\n",t[(i+d)%4].y);
	}
}
posted @ 2019-02-22 07:42  Stargazer_cykoi  阅读(169)  评论(0编辑  收藏  举报