1. 程式人生 > >bzoj 1185 最小矩形覆蓋 —— 旋轉卡殼

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\n",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\n",pos[i].x,pos[i].y); return 0; }