【BZOJ1185】最小矩形覆盖(HNOI2007)-旋转卡壳
测试地址:最小矩形覆盖
做法:本题需要用到旋转卡壳。
根据直觉(实际上是我不会证),最小的矩形的一边一定在凸包上,于是我们在凸包上枚举其中的一边,顺便开三个指针求出对踵点,以及在当前边方向上最远的两个点,即可求出矩形挨着的点,这样就可以求出矩形的其它三个点了。于是我们就解决了这一题,求凸包的时间复杂度为,后面算法的时间复杂度为。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int n,top,st[100010];
struct point
{
double x,y;
}p[50010],ans[4],now[4];
point operator + (point a,point b) {point s={a.x+b.x,a.y+b.y};return s;}
point operator - (point a,point b) {point s={a.x-b.x,a.y-b.y};return s;}
point operator * (point a,double b) {point s={a.x*b,a.y*b};return s;}
double operator * (point a,point b) {return a.x*b.y-a.y*b.x;}
double dis(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(point a,point b)
{
if (fabs((a-p[1])*(b-p[1]))<eps)
return dis(a,p[1])<dis(b,p[1]);
else return (a-p[1])*(b-p[1])>0;
}
void init()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
if (i>1&&(p[i].x<p[1].x||(p[i].x-p[1].x<eps&&p[i].y<p[1].y)))
swap(p[1],p[i]);
}
sort(p+2,p+n+1,cmp);
}
void graham_scan()
{
st[1]=top=1;
for(int i=2;i<=n;i++)
{
while(top>1&&(p[st[top]]-p[st[top-1]])*(p[i]-p[st[top]])<eps) top--;
st[++top]=i;
}
}
point inter(point p,point v,point q,point w)
{
point u=p-q;
double t=(w*u)/(v*w);
return p+v*t;
}
void work()
{
for(int i=1;i<=top;i++)
st[top+i]=st[top*2+i]=st[top*3+i]=st[i];
st[0]=st[top];
int x=0,y=2,z=1;
double mn=1e18;
for(int i=1;i<=top;i++)
{
point p1,p2,p3,p4;
p1=p[st[i+1]]-p[st[i]];
p2.x=-p1.y,p2.y=p1.x;
p3.x=-p1.x,p3.y=-p1.y;
p4.x=-p2.x,p4.y=-p2.y;
while(p3*(p[st[z+1]]-p[st[z]])<eps) z++;
if (i==1) x=z;
while(p4*(p[st[x+1]]-p[st[x]])<eps) x++;
while(p2*(p[st[y+1]]-p[st[y]])<eps) y++;
now[0]=inter(p[st[i]],p1,p[st[y]],p2);
now[1]=inter(p[st[y]],p2,p[st[z]],p3);
now[2]=inter(p[st[z]],p3,p[st[x]],p4);
now[3]=inter(p[st[x]],p4,p[st[i]],p1);
if ((now[1]-now[0])*(now[3]-now[0])<mn)
{
mn=(now[1]-now[0])*(now[3]-now[0]);
for(int i=0;i<4;i++) ans[i]=now[i];
}
}
printf("%.5lf\n",mn);
double mnx=1e18,mny=1e18;
int mni;
for(int i=0;i<4;i++)
if (ans[i].y<mny||(ans[i].y-mny<eps&&ans[i].x<mnx))
{
mnx=ans[i].x;
mny=ans[i].y;
mni=i;
}
for(int i=mni;i<4;i++) printf("%.5lf %.5lf\n",ans[i].x,ans[i].y);
for(int i=0;i<mni;i++) printf("%.5lf %.5lf\n",ans[i].x,ans[i].y);
}
int main()
{
init();
graham_scan();
work();
return 0;
}