suxxsfe

一言(ヒトコト)

UVA10173 Smallest Bounding Rectangle

最小矩形覆盖,旋转卡壳
https://www.luogu.com.cn/problem/UVA10173

先求出凸包,那么一个结论就是最终这个矩形必然有一边必然和凸包的某一边重合
于是我们就旋转卡壳枚举这个边,再另外维护三个指针,分别表示距离这个边最远的点,以目前这个线段的方向为正方向,最靠前、靠后的点,或者说是旋转整个凸包使得目前的线段平行于 \(x\) 轴时,横坐标最大、最小的点
第一个指针好维护,只要叉积算面积即可,另外两个需要用点积判他和他后一个点组成的线段是否与当前线段同向/反向
于是此时的矩形就要一边和这个线段重合、另外三边卡在这三个点上
那么只要实现点到线段距离即可求出矩形长、宽,从而得到面积

一个细节是维护上面那个“最靠后”的指针时,初始值要赋为离第一条线段最远的点

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define reg register
#define EN puts("")
#define INT_INF ((int)0x3f3f3f3f)
#define LL_INF ((long long)0x3f3f3f3f3f3f3f3f)
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
	return y?x:-x;
}
#define N 1006
#define PI 3.1415926575898
struct Vector{
	double x,y,ang;
	inline int operator < (const Vector &b)const{return ang==b.ang?(x==b.x?y<b.y:x<b.x):ang>b.ang;}
	inline double len(){return std::sqrt(x*x+y*y);}
	inline Vector operator - (const Vector &b)const{return (Vector){x-b.x,y-b.y,0};}
	inline Vector operator + (const Vector &b)const{return (Vector){x+b.x,y+b.y,0};};
	inline Vector operator * (const double &b)const{return (Vector){x*b,y*b,0};}
	inline double operator ^ (const Vector b)const{return x*b.y-y*b.x;}
	inline double operator * (const Vector &b)const{return x*b.x+y*b.y;}
};
inline double dis(Vector a,Vector b,Vector c){return std::abs(((c-a)^(c-b))/(a-b).len());}
inline int graham(int n,Vector *p,Vector *stack){
	for(reg int i=2;i<=n;i++)if(p[i]<p[1]) std::swap(p[i],p[1]);
	for(reg int i=2;i<=n;i++) p[i].ang=atan2(p[i].y-p[1].y,p[i].x-p[1].x);
	std::sort(p+2,p+1+n);
	stack[1]=p[1];int top=1;
	for(reg int i=2;i<=n;i++){
		while(top>1&&((p[i]-stack[top])^(stack[top]-stack[top-1]))<=0) top--;
		stack[++top]=p[i];
	}
	stack[++top]=p[1];
	return top;
}
int n;
Vector p[N],q[N];
inline int nex(reg int i){return i==n?2:(i+1);}
int main(){
while(n=read()){
	for(reg int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y),p[i].ang=0;
	if(n<=2){puts("0.0000");continue;}
	n=graham(n,p,q);
	if(n<=3){puts("0.0000");continue;}
	double ans=1e18;
	Vector o;
	reg int j=3,h=1,g;
	while(std::abs((q[j]-q[1])^(q[j]-q[2]))<=std::abs((q[nex(j)]-q[1])^(q[nex(j)]-q[2]))) j=nex(j);
	g=j;
	for(reg int i=1;i<n;i++){
		while(std::abs((q[j]-q[i])^(q[j]-q[i+1]))<=std::abs((q[nex(j)]-q[i])^(q[nex(j)]-q[i+1]))) j=nex(j);
		while((q[nex(h)]-q[h])*(q[i+1]-q[i])>=0) h=nex(h);
		while((q[nex(g)]-q[g])*(q[i]-q[i+1])>=0) g=nex(g);
		Vector o=(Vector){q[i].y-q[i+1].y,q[i+1].x-q[i].x};
		ans=std::min(ans,dis(q[i],q[i+1],q[j])*dis(q[h],q[h]+o,q[g]));
	}
	printf("%.4lf\n",ans);
}
	return 0;
}
posted @ 2021-06-25 15:26  suxxsfe  阅读(80)  评论(0编辑  收藏  举报