bzoj 1185 最小矩形覆盖 —— 旋转卡壳

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1185 最小矩形覆盖 —— 旋转卡壳相关的知识,希望对你有一定的参考价值。

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1185

枚举一条边,维护上、左、右方的点;

上方点到这条边距离最远,所以用叉积求面积维护;

左右点到这条边的射影最长(!),所以用点积求射影维护;

因为维护的点是只能逆时针走的,所以初始的左边点要特殊处理一下,其实等于右边点即可,然后可以走过去到合适位置;

然后维护矩形的四个端点,就是根据距离,从边的端点走过去,还挺有意思的。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef double db;
db const eps=1e-8;
int const xn=50005;
int n;
db ans;
int dmp(db x){if(fabs(x)<=eps)return 0; return x>eps?1:-1;}
struct P{
  db x,y;
  P(db x=0,db y=0):x(x),y(y) {}
  bool operator < (const P &b) const
  {return dmp(x-b.x)<0||dmp(x-b.x)==0&&dmp(y-b.y)<0;}
  P operator + (const P &b) const
  {return P(x+b.x,y+b.y);}
  P operator - (const P &b) const
  {return P(x-b.x,y-b.y);}
  P operator * (const db &v) const
  {return P(x*v,y*v);}
  P operator / (const db &v) const
  {return P(x/v,y/v);}
}p[xn],c[xn],pos[5];
db cross(P a,P b){return a.x*b.y-a.y*b.x;}
db dot(P a,P b){return a.x*b.x+a.y*b.y;}
void find()
{
  sort(p+1,p+n+1); int top=0;
  for(int i=1;i<=n;i++)
    {
      while(top>1&&dmp(cross(c[top]-c[top-1],p[i]-c[top]))<=0)top--;
      c[++top]=p[i];
    }
  int num=top;
  for(int i=n-1;i;i--)
    {
      while(top>num&&dmp(cross(c[top]-c[top-1],p[i]-c[top]))<=0)top--;
      c[++top]=p[i];
    }
  n=top-1;
}
int upt(int x){if(x>n)x-=n; if(x<1)x+=n; return x;}
db sqr(db x){return x*x;}
db dis(P a,P b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
bool cmp(P a,P b){return dmp(a.y-b.y)<0||(dmp(a.y-b.y)==0&&dmp(a.x-b.x)<0);}
void rc()
{
  ans=-1;
  //int p=2,l=1,r=2;//
  int p=2,l=2,r=2; c[n+1]=c[1];
  for(int i=1;i<=n;i++)
    {
      db d=dis(c[i],c[i+1]);
      while(dmp(cross(c[i]-c[p],c[i+1]-c[p])-cross(c[i]-c[p+1],c[i+1]-c[p+1]))<=0)p=upt(p+1);
      while(dmp(dot(c[r]-c[i],c[i+1]-c[i])-dot(c[r+1]-c[i],c[i+1]-c[i]))<=0)r=upt(r+1);
      if(i==1)l=r;//
      while(dmp(dot(c[l]-c[i],c[i+1]-c[i])-dot(c[l+1]-c[i],c[i+1]-c[i]))>=0)l=upt(l+1);
      db L=dot(c[i+1]-c[i],c[l]-c[i])/d;
      db R=dot(c[i+1]-c[i],c[r]-c[i])/d;
      db H=cross(c[i]-c[p],c[i+1]-c[p])/d;
      db tmp=(R-L)*H;
      if(ans<0||dmp(ans-tmp)>0)
    {
      ans=tmp;
      pos[0]=c[i]+(c[i+1]-c[i])*(R/d);
      pos[1]=pos[0]+(c[r]-pos[0])*(H/dis(c[r],pos[0]));
      //pos[2]=pos[1]+(c[p]-pos[1])*((R-L)/dis(c[p],pos[1]));//也可
      pos[2]=pos[1]+(c[i]-pos[0])*((R-L)/dis(c[i],pos[0]));
      pos[3]=pos[2]+(pos[0]-pos[1]);
    }
    }
}
int main()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
  find(); 
  rc();
  printf("%.5f
",ans);
  int st=0;
  for(int i=1;i<4;i++)if(cmp(pos[i],pos[st]))st=i;
  for(int i=st,cnt=1;cnt<=4;i=(i+1)%4,cnt++)
      printf("%.5f %.5f
",pos[i].x,pos[i].y);
  return 0;
}

 

以上是关于bzoj 1185 最小矩形覆盖 —— 旋转卡壳的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1185 最小矩形覆盖 —— 旋转卡壳

BZOJ1185: [HNOI2007]最小矩形覆盖

bzoj1185: [HNOI2007]最小矩形覆盖

模板计几最小矩形覆盖(bzoj1185)

●BZOJ 1185 [HNOI2007]最小矩形覆盖

bzoj 1185