UVA 12307 Smallest Enclosing Rectangle

时间:2023-03-09 02:56:49
UVA 12307 Smallest Enclosing Rectangle

https://vjudge.net/problem/UVA-12307

求覆盖所有点的最小矩形面积、周长

相当于求凸包的最小面积外接矩形、最小周长外接矩形

结论:

这个矩形一定有一条边和凸包上一条边重合

证明去看https://wenku.baidu.com/view/f11d0836ee06eff9aef807d9.html

UVA 12307 Smallest Enclosing Rectangle

枚举一条边,用旋转卡壳求其他三边

假设现在正枚举到A点,对应紫色边,

显然,紫色边的对边一定 过A点的对踵点且与紫色边平行

那么矩形的高|BH|=AE、AB的叉积/ | AB |

现在只剩下|GD|

把向量CD平移至向量AF

|GD|=cos(∠CDG)*|CD|=cos(∠CDG)*|AF|

AF*AD=|AF|*|AD|*cos(∠DAF)

∵∠CDG=∠DAF

∴AF*AD=|GD|*|AD|

所以|GD|=AF*AD/|AD|

点A是枚举的,如何求点B C K?

上面说了,点B是点A的对踵点,

那么利用叉积,同底三角形面积越大,高越大 即可求出B点

直观上看,K点是距点A最靠右的点

即沿向量AD向右扩展

向右就可以想到两个向量点积>0

即下一个点与这个点组成的向量,如果AD与它的点积>0,K取下一个点更优

C点同理,点积<0

注意C是从点B开始逆时针寻找的最靠左的点

#include<cmath>
#include<cstdio>
#include<algorithm> #define N 100001 using namespace std; const double eps=1e-; int dcmp(double x)
{
if(fabs(x)<eps) return ;
return x< ? - : ;
} struct Point
{
double x,y; Point(double x=,double y=) : x(x),y(y) { } bool operator < (Point p) const
{
if(!dcmp(x-p.x)) return y<p.y;
return x<p.x;
} bool operator == (Point p) const
{
return !dcmp(x-p.x) && !dcmp(y-p.y);
}
}; typedef Point Vector; Point P[N],C[N]; Vector operator - (Vector A,Vector B) { return Vector(A.x-B.x,A.y-B.y); } double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
} double Area2(Point A,Point B,Point D)
{
return Cross(B-A,D-A);
} double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
} double Length(Vector A)
{
return sqrt(Dot(A,A));
} int ConvexHull(Point *p,int n,Point *c)
{
sort(p,p+n);
n=unique(p,p+n)-p;
int m=;
for(int i=;i<n;++i)
{
while(m> && Cross(c[m-]-c[m-],p[i]-c[m-])<=)
m--;
c[m++]=p[i];
}
int k=m;
for(int i=n-;i>=;--i)
{
while(m>k && Cross(c[m-]-c[m-],p[i]-c[m-])<=)
m--;
c[m++]=p[i];
}
m--;
return m;
} void RotatingCaliper(Point *c,int m)
{
double AnsArea=1e20,AnsPeri=1e20;
int q=,l=,r=;
double d,h,w;
for(int p=;p<m;++p)
{
while(fabs(Cross(c[p]-c[p+],c[q+]-c[p+]))>fabs(Cross(c[p]-c[p+],c[q]-c[p+]))) q=(q+)%m;
while(dcmp(Dot(c[p+]-c[p],c[r+]-c[r]))>) r=(r+)%m;
if(!l) l=q;
while(dcmp(Dot(c[p+]-c[p],c[l+]-c[l]))<) l=(l+)%m;
d=Length(c[p+]-c[p]);
h=fabs(Area2(c[p],c[p+],c[q]))/d;
w=Dot(c[p+]-c[p],c[r]-c[l])/d;
AnsArea=min(AnsArea,w*h);
AnsPeri=min(AnsPeri,(w+h)*);
}
printf("%.2lf %.2lf\n",AnsArea,AnsPeri);
} int main()
{
int n,m;
while()
{
scanf("%d",&n);
if(!n) return ;
for(int i=;i<n;++i) scanf("%lf%lf",&P[i].x,&P[i].y);
m=ConvexHull(P,n,C);
RotatingCaliper(C,m);
}
}