[HNOI2007]最小矩形覆盖
作者:互联网
传送门
先求出凸包,然后枚举凸包上的每条边作为矩形的一边。
做出对应的另外三条边——用叉积判断即可
(代码中cross注意是>0,而不是≥0。)
注意输出的−0.00000要调整成0.00000
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double inf=1e10;
const int maxn=5e4+10;
int n,k,top,D,E,F,ansD,ansE,ansF;
double x,y,tot=inf;
inline int sgn(double x){
if(x>eps) return 1;
if(x<-eps) return -1;
return 0;
}
inline int add(int x){return x+1>top?x+1-top:x+1;}
inline int dec(int x){return x-1==0?top:x-1;}
inline double Out(double x){return sgn(x)==0?0:x;}
struct Grid{
double x,y,Angle;
Grid(double X=0,double Y=0,double Ang=0){x=X,y=Y,Angle=atan2(y,x);}
friend inline Grid operator+(const Grid &a,const Grid &b){return Grid(a.x+b.x,a.y+b.y);}
friend inline Grid operator-(const Grid &a,const Grid &b){return Grid(a.x-b.x,a.y-b.y);}
friend inline Grid operator*(const Grid &a,const double &b){return Grid(a.x*b,a.y*b);}
friend inline Grid operator/(const Grid &a,const double &b){return Grid(a.x/b,a.y/b);}
friend inline double cross(const Grid &a,const Grid &b){return a.x*b.y-a.y*b.x;}
inline Grid perpendicular(){return Grid(-y,x);}
inline void print(){
printf("%.5lf %.5lf\n",Out(x),Out(y));
}
}p[maxn],s[maxn],M[5],ans[5];typedef Grid Vector,Point;
inline double dis(const Point &a,const Point &b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
inline bool cmp(const Point &a,const Point &b){
double A=atan2(a.y-p[1].y,a.x-p[1].x);
double B=atan2(b.y-p[1].y,b.x-p[1].x);
if(A!=B) return A<B;
return a.x<b.x;
}
inline bool cmp2(const Point &a,const Point &b){
double A=atan2(a.y-ans[1].y,a.x-ans[1].x);
double B=atan2(b.y-ans[1].y,b.x-ans[1].x);
if(A!=B) return A<B;
return a.x<b.x;
}
struct Line{
Point s,t;
Line(Point S=Point(),Point T=Point()){s=S,t=T;}
friend inline Point Intersection(const Line &a,const Line &b)
{return a.s+(a.t-a.s)*cross(b.t-b.s,a.s-b.s)/cross(a.t-a.s,b.t-b.s);}
inline void print(){
puts("Line");
s.print(),t.print();
}
};
inline void Graham(){
swap(p[k],p[1]),sort(p+2,p+n+1,cmp);
s[1]=p[1],s[top=2]=p[2];
for(int i=3;i<=n;++i){
while(top>=2&&sgn(cross(p[i]-s[top-1],s[top]-s[top-1])>=0)) --top;
s[++top]=p[i];
}s[top+1]=p[1];
}
inline double calc(Line a,Line b,Line c,Line d){
M[1]=Intersection(a,b),M[2]=Intersection(b,c),
M[3]=Intersection(c,d),M[4]=Intersection(d,a);
return dis(M[1],M[2])*dis(M[2],M[3]);
}
int main(){
//freopen("1986.in","r",stdin);
scanf("%d",&n),ans[0]=p[0]=Point(inf,inf);
for(int i=1;i<=n;++i){
scanf("%lf%lf",&x,&y),p[i]=Point(x,y);
if(p[0].y>p[i].y||(p[0].y==p[i].y&&p[0].x>p[i].x)){p[0]=p[i],k=i;}
}Graham(),D=2;
for(int i=1;i<=top;++i){
Vector A=Vector(s[i+1]-s[i]).perpendicular();//垂直向量 (逆时针90°)
Vector B=A.perpendicular();//反向平行向量
Vector C=B.perpendicular();//逆时针270°
while(cross(s[add(D)]-s[D],A)>0) D=add(D);E=D;
while(cross(s[add(E)]-s[E],B)>0) E=add(E);F=E;
while(cross(s[add(F)]-s[F],C)>0) F=add(F);
double now=calc(Line(s[i],s[i+1]),Line(s[D],s[D]+A),Line(s[E],s[E]+B),Line(s[F],s[F]+C));
if(now<tot){for(int i=1;i<=4;++i) ans[i]=M[i];tot=now;}
}
for(int i=1;i<=4;++i)
if(ans[0].y>ans[i].y||(ans[0].y==ans[i].y&&ans[0].x>ans[i].x)){ans[0]=ans[i],k=i;}
swap(ans[k],ans[1]),sort(ans+2,ans+5,cmp2);
printf("%.5lf\n",Out(tot));
for(int i=1;i<=4;++i) ans[i].print();
}
标签:const,double,ans,最小,return,Grid,HNOI2007,inline,矩形 来源: https://blog.csdn.net/g21wcr/article/details/96881631