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 最小矩形覆盖 —— 旋转卡壳的主要内容,如果未能解决你的问题,请参考以下文章