2018.10.18 bzoj1185: [HNOI2007]最小矩形覆盖(旋转卡壳)

传送门
不难看出最后的矩形一定有一条边与凸包某条边重合。
因此先求出凸包,然后旋转卡壳求出当前最小矩形面积更新答案。
代码:

#include
#define N 50005
#define eps 1e-9
using namespace std;
struct pot{
	long double x,y;
	inline pot operator+(const pot&a){return (pot){x+a.x,y+a.y};} 
	inline pot operator-(const pot&a){return (pot){x-a.x,y-a.y};}
	inline long double operator^(const pot&a){return x*a.y-y*a.x;}
	inline long double operator*(const pot&a){return x*a.x+y*a.y;}
	inline pot operator*(const long double&a){return (pot){x*a,y*a};} 
	inline long double dist(){return sqrt(x*x+y*y);}
	friend inline bool operator<(pot a,pot b){return fabs(a.y-b.y)<eps?a.x<b.x:a.y<b.y;}
	inline pot rev(){return (pot){-y,x};}
}p[N],ans[5],now[5];
int n,q[N],top=0;
long double sum=1e18;
inline bool cmp(pot x,pot y){
	long double tmp=(x-p[1])^(y-p[1]);
	if(fabs(tmp)>eps)return tmp>0;
	return (x-p[1]).dist()<(y-p[1]).dist(); 
}
inline void graham(){
	int tmp=1;
	for(int i=2;i<=n;++i)if(p[i]<p[tmp])tmp=i;
	if(tmp^1)swap(p[tmp],p[1]);
	sort(p+2,p+n+1,cmp),q[++top]=1;
	for(int i=2;i<=n;++i){
		while(top>=2&&((p[q[top]]-p[q[top-1]])^(p[i]-p[q[top-1]]))<eps)--top;
		q[++top]=i;
	}
	q[0]=q[top];
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%Lf%Lf",&p[i].x,&p[i].y);
	graham();
	for(int i=0,l=1,r=1,h=1;i<top;++i){
		long double Dis=(p[q[i+1]]-p[q[i]]).dist();
		while(((p[q[i+1]]-p[q[i]])^(p[q[h+1]]-p[q[i]]))-((p[q[i+1]]-p[q[i]])^(p[q[h]]-p[q[i]]))>-eps)h=(h+1)%top;
		while((p[q[i+1]]-p[q[i]])*(p[q[r+1]]-p[q[i]])-(p[q[i+1]]-p[q[i]])*(p[q[r]]-p[q[i]])>-eps)r=(r+1)%top;
		if(!i)l=r;
		while((p[q[i+1]]-p[q[i]])*(p[q[l+1]]-p[q[i]])-(p[q[i+1]]-p[q[i]])*(p[q[l]]-p[q[i]])<eps)l=(l+1)%top;
		long double L=(p[q[i+1]]-p[q[i]])*(p[q[l]]-p[q[i]])/Dis,R=(p[q[i+1]]-p[q[i]])*(p[q[r]]-p[q[i]])/Dis;
		long double H=fabs(((p[q[i+1]]-p[q[i]])^(p[q[h]]-p[q[i]]))/Dis),tmp=(R-L)*H;
		if(tmp<sum){
			sum=tmp;
			ans[1]=p[q[i]]+(p[q[i+1]]-p[q[i]])*(R/Dis);
			ans[2]=ans[1]+(p[q[r]]-ans[1])*(H/(ans[1]-p[q[r]]).dist());
			ans[3]=ans[2]-(ans[1]-p[q[i]])*((R-L)/(p[q[i]]-ans[1]).dist());
			ans[4]=ans[3]+ans[1]-ans[2];
		}
	}
	printf("%.5Lf\n",sum);
	int pos=1;
	for(int i=1;i<=4;++i){
		if(fabs(ans[i].x)<eps)ans[i].x=0;
		if(fabs(ans[i].y)<eps)ans[i].y=0;
	}
	for(int i=2;i<=4;++i)if(ans[i]<ans[pos])pos=i;
	for(int i=1;i<=4;++i){
		printf("%.5Lf %.5Lf\n",ans[pos].x,ans[pos].y);
		++pos;
		if(pos==5)pos=1;
	}
	for(int i=1;i<=10;++i)puts("");
	return 0;
}

你可能感兴趣的:(#,凸包,#,计算几何,#,旋转卡壳,-----计算几何-----)