[HNOI2007]最小矩形覆盖

传送门
先求出凸包,然后枚举凸包上的每条边作为矩形的一边。
做出对应的另外三条边——用叉积判断即可
(代码中 c r o s s cross cross注意是 > 0 >0 0,而不是 ≥ 0 ≥0 0。)
注意输出的 − 0.00000 -0.00000 0.00000要调整成 0.00000 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();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值