1185: [HNOI2007]最小矩形覆盖
题目描述
给定一些点的坐标,要求求能够覆盖所有点的最小面积的矩形,
输出所求矩形的面积和四个顶点坐标
输入
第一行为一个整数n(3<=n<=50000)
从第2至第n+1行每行有两个浮点数,表示一个顶点的x和y坐标,不用科学计数法
输出
第一行为一个浮点数,表示所求矩形的面积(精确到小数点后5位),
接下来4行每行表示一个顶点坐标,要求第一行为y坐标最小的顶点,
其后按逆时针输出顶点坐标.如果用相同y坐标,先输出最小x坐标的顶点
样例输入
6 1.0 3.00000
1 4.00000
2.0000 1
3 0.0000
3.00000 6
6.0 3.0
1 4.00000
2.0000 1
3 0.0000
3.00000 6
6.0 3.0
样例输出
18.00000
3.00000 0.00000
6.00000 3.00000
3.00000 6.00000
0.00000 3.00000
3.00000 0.00000
6.00000 3.00000
3.00000 6.00000
0.00000 3.00000
暴力过的,先把坐标旋转,计算新坐标系下所有点的新的坐标,找到4个角,然后把4个角的坐标转成原坐标系下的坐标,时间复杂度O(n^2),涉及角度转换,时间常数也很大
#include<iostream> #include<stdio.h> #include<math.h> #include<algorithm> using namespace std; typedef struct { double x,y; }Point; Point p[50005]; int n; int Q[50005],top; int ans[50005]; bool cmp(Point a,Point b){ return a.y<b.y||(a.y==b.y&&a.x<b.x); } double cross(int i,int j,int k){ Point a=p[i]; Point b=p[j]; Point c=p[k]; return (c.x-b.x)*(a.y-b.y)-(c.y-b.y)*(a.x-b.x); } void scan(){ sort(p+1,p+1+n,cmp); Q[1]=1;Q[2]=2;top=2; for(int i=3;i<=n;++i) { while(top>1&&cross(Q[top-1],Q[top],i)<=0) top--; Q[++top]=i; } ans[0]=top; for(int i=1;i<=top;++i) ans[i]=Q[i]; Q[1]=n;Q[2]=n-1;top=2; for(int i=n-2;i>=1;--i) { while(top>1&&cross(Q[top-1],Q[top],i)<=0) top--; Q[++top]=i; } for(int i=2;i<top;++i) { ans[0]++; ans[ans[0]]=Q[i]; } } double computeTheta(int i,int j){ Point a=p[i]; Point b=p[j]; if(a.y>b.y) {Point c=a;a=b;b=c;} // cout<<(b.x-a.x)<<" "<<sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))<<" "<<(b.x-a.x)/sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))<<" "<<acos((b.x-a.x)/sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y)))<<endl; return acos((b.x-a.x)/sqrt((b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y))); } bool isBetter(Point tempPoint[],Point ansPoint[]){ for(int i=0;i<3;++i) { if(tempPoint[i].y<ansPoint[i].y||(tempPoint[i].y==ansPoint[i].y&&tempPoint[i].x<ansPoint[i].x)) return true; if(tempPoint[i].y>ansPoint[i].y||(tempPoint[i].y==ansPoint[i].y&&tempPoint[i].x>ansPoint[i].x)) return false; } return false; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lf %lf",&p[i].x,&p[i].y); scan(); ans[0]++; ans[ans[0]]=1; double x,y; double minarea; bool initialArea=true; double minx,maxx,miny,maxy; bool initialXY=true; Point ansPoint[4]; for(int i=1;i<ans[0];++i) { // cout<<p[ans[i]].x<<" "<<p[ans[i]].y<<" "<<p[ans[i+1]].x<<" "<<p[ans[i+1]].y<<endl; double theta=computeTheta(ans[i],ans[i+1]); initialXY=true; for(int j=1;j<ans[0];++j) { x=p[ans[j]].x*cos(theta)+p[ans[j]].y*sin(theta); y=p[ans[j]].y*cos(theta)-p[ans[j]].x*sin(theta); if(initialXY==true) { minx=x;maxx=x;miny=y;maxy=y; initialXY=false; } if(initialArea==false&&(maxx-minx)*(maxy-miny)>minarea+0.5) break; if(x<minx) minx=x; if(x>maxx) maxx=x; if(y<miny) miny=y; if(y>maxy) maxy=y; } // cout<<theta<<" "<<(maxx-minx)*(maxy-miny)<<" fdg"<<endl; if(initialArea==true||(maxx-minx)*(maxy-miny)<minarea) { initialArea=false; minarea=(maxx-minx)*(maxy-miny); ansPoint[0].x=minx*cos(theta)-miny*sin(theta); ansPoint[0].y=minx*sin(theta)+miny*cos(theta); ansPoint[1].x=minx*cos(theta)-maxy*sin(theta); ansPoint[1].y=minx*sin(theta)+maxy*cos(theta); ansPoint[2].x=maxx*cos(theta)-miny*sin(theta); ansPoint[2].y=maxx*sin(theta)+miny*cos(theta); ansPoint[3].x=maxx*cos(theta)-maxy*sin(theta); ansPoint[3].y=maxx*sin(theta)+maxy*cos(theta); } else if(initialArea==false&&fabs((maxx-minx)*(maxy-miny)-minarea)<1e-6) { // cout<<"NOW "<<(maxx-minx)*(maxy-miny)<<endl; Point tempPoint[4]; tempPoint[0].x=minx*cos(theta)-miny*sin(theta); tempPoint[0].y=minx*sin(theta)+miny*cos(theta); tempPoint[1].x=minx*cos(theta)-maxy*sin(theta); tempPoint[1].y=minx*sin(theta)+maxy*cos(theta); tempPoint[2].x=maxx*cos(theta)-miny*sin(theta); tempPoint[2].y=maxx*sin(theta)+miny*cos(theta); tempPoint[3].x=maxx*cos(theta)-maxy*sin(theta); tempPoint[3].y=maxx*sin(theta)+maxy*cos(theta); sort(ansPoint,ansPoint+4,cmp); sort(tempPoint,tempPoint+4,cmp); if(isBetter(tempPoint,ansPoint)) { ansPoint[0]=tempPoint[0]; ansPoint[1]=tempPoint[1]; ansPoint[2]=tempPoint[2]; ansPoint[3]=tempPoint[3]; } } } printf("%.5f\n",minarea); for(int i=0;i<=3;++i) { if(fabs(ansPoint[i].x)<1e-6) ansPoint[i].x=0; if(fabs(ansPoint[i].y)<1e-6) ansPoint[i].y=0; } n=4; for(int i=1;i<=4;++i) p[i]=ansPoint[i-1]; scan(); for(int i=1;i<=4;++i) printf("%.5f %.5f\n",p[ans[i]].x,p[ans[i]].y); return 0; }
看到其他人的题解,挺好的,旋转卡壳,时间复杂度O(N),下面这个代码很优雅,侵删
#include<bits/stdc++.h> #define db double using namespace std; const int M=5e4+5; const db eps=1e-8; struct pt{db x,y;}; int sig(db x){return (x>eps)-(x<-eps);} pt operator -(pt a,pt b){return (pt){a.x-b.x,a.y-b.y};} pt operator +(pt a,pt b){return (pt){a.x+b.x,a.y+b.y};} db operator *(pt a,pt b){return a.x*b.y-a.y*b.x;} db operator /(pt a,pt b){return a.x*b.x+a.y*b.y;} pt operator *(pt a,db b){return (pt){a.x*b,a.y*b};} pt operator /(pt a,db b){return (pt){a.x/b,a.y/b};} bool operator <(pt a,pt b){return !sig(a.y-b.y)?a.x<b.x:a.y<b.y;} db area(pt a,pt b,pt c){return (b-a)*(c-a);} db shad(pt a,pt b,pt c){return (b-a)/(c-a);} db sqr(db x){return x*x;} db dis(pt a,pt b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));} bool cmp(pt a,pt b){return sig(a.x-b.x)?a.y<b.y:a.x<b.x;} pt p[M],sta[M],rec[5]; int top,n; void in() { scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y); } void tubao() { top=-1; sort(p+1,p+1+n); for(int i=1;i<=n;++i) { while(top>0&&sig(area(sta[top-1],sta[top],p[i]))<=0)--top; sta[++top]=p[i]; } int k=top; for(int i=n-1;i>=1;--i) { while(top>k&&sig(area(sta[top-1],sta[top],p[i]))<=0)--top; sta[++top]=p[i]; } } int x[M]; db fuck(db x){return !sig(x)?fabs(x):x;} void ac() { int le=1,ri=1,up=1; db L,R,H,D,tmp,ans=1e60; for(int i=0;i<top;++i) { D=dis(sta[i],sta[i+1]); while(sig(area(sta[i],sta[i+1],sta[up])-area(sta[i],sta[i+1],sta[up+1]))<=0)up=(up+1)%top; while(sig(shad(sta[i],sta[i+1],sta[ri])-shad(sta[i],sta[i+1],sta[ri+1]))<=0)ri=(ri+1)%top; if(i==0)le=up; while(sig(shad(sta[i],sta[i+1],sta[le])-shad(sta[i],sta[i+1],sta[le+1]))>=0)le=(le+1)%top; L=shad(sta[i],sta[i+1],sta[le])/D; R=shad(sta[i],sta[i+1],sta[ri])/D; H=area(sta[i],sta[i+1],sta[up])/D; H=H>0?H:-H; tmp=(R-L)*H; if(tmp<ans) { ans=tmp; rec[0]=sta[i]+(sta[i+1]-sta[i])*(R/D); rec[1]=rec[0]+(sta[ri]-rec[0])*(H/dis(sta[ri],rec[0])); rec[2]=rec[1]-(rec[0]-sta[i])*((R-L)/dis(sta[i],rec[0])); rec[3]=rec[2]-(rec[1]-rec[0]); } } ans=fabs(ans); printf("%.5lf\n",ans); int fir=0; for(int i=1;i<=3;++i) if(rec[i]<rec[fir])fir=i; for(int i=0;i<=3;++i) printf("%.5lf %.5lf\n",fuck(rec[(i+fir)%4].x),fuck(rec[(i+fir)%4].y)); } int main() { in();tubao(); ac(); return 0; }