用旋转卡壳做。先求出凸包,枚举每一条边作为矩形的一边。画画图可以看出另外三个点的决策应该是单调的。对面的点用叉乘看三角形面积大小判断,两边的点用点乘看向量在已固定的边上投影的长度(即矩形的宽)判断。注意第一次的两侧定点应分别从对面定点的两侧开始判断,需要赋初值。然后用点到直线距离,两直线交点等数学运算求一求就好了。具体看代码注释吧。最后需要避免因精度问题输出-0.00000,所以整体加一个eps。
#include
#include
#include
using namespace std;
const int N=50010;
const double eps=0.0000001;
struct node{
double x,y;
}p1[N],ans[5];
double xx,yy,mn,a1,b1,c1,a2,b2,c2,a3,b3,c3,a4,b4,c4,h1,h2,hb,hc;
int n,top,sta[N],s,aa,bb,cc;
inline double cross(node a,node b,node c){
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
inline double dot(node a,node b,node c){
return (b.x-a.x)*(c.x-a.x)+(b.y-a.y)*(c.y-a.y);
}
inline double dist(node p,double a,double b,double c){
double ans1=a*p.x+b*p.y+c;if(ans1<0)ans1=-ans1;
return ans1/sqrt(a*a+b*b);
}
bool cmp(node i,node j){
if(atan2(i.y-yy,i.x-xx)!=atan2(j.y-yy,j.x-xx))return atan2(i.y-yy,i.x-xx)1&&cross(p1[sta[top-1]],p1[sta[top]],p1[i])<=0)--top;
sta[++top]=i;
}
if(top<3){
printf("0.00000\n");
if(top==1)for(int i=1;i<=4;++i)printf("%.5lf %.5lf\n",p1[sta[1]].x,p1[sta[1]].y);
else{
for(int i=1;i<=2;++i)printf("%.5lf %.5lf\n",p1[sta[1]].x,p1[sta[1]].y);
for(int i=1;i<+2;++i)printf("%.5lf %.5lf\n",p1[sta[2]].x,p1[sta[2]].y);
}
return 0;
}
sta[top+1]=sta[1],aa=bb=cc=2,mn=1e16;
for(int i=1;i<=top;++i){
while(cross(p1[sta[i+1]],p1[sta[i]],p1[sta[aa+1]])<=cross(p1[sta[i+1]],p1[sta[i]],p1[sta[aa]]))aa=aa%top+1;
if(i==1)bb=aa;
while(dot(p1[sta[i]],p1[sta[i+1]],p1[sta[bb+1]])<=dot(p1[sta[i]],p1[sta[i+1]],p1[sta[bb]]))bb=bb%top+1;
while(dot(p1[sta[i+1]],p1[sta[i]],p1[sta[cc+1]])<=dot(p1[sta[i+1]],p1[sta[i]],p1[sta[cc]]))cc=cc%top+1;
//求a到直线i,i+1的距离h1
a1=p1[sta[i+1]].y-p1[sta[i]].y,b1=p1[sta[i]].x-p1[sta[i+1]].x,
c1=p1[sta[i+1]].x*p1[sta[i]].y-p1[sta[i+1]].y*p1[sta[i]].x;
h1=dist(p1[sta[aa]],a1,b1,c1);
//构建a到i,i+1的垂线
a2=p1[sta[i]].x-p1[sta[i+1]].x,b2=p1[sta[i]].y-p1[sta[i+1]].y,
c2=p1[sta[aa]].y*(p1[sta[i+1]].y-p1[sta[i]].y)-p1[sta[aa]].x*(p1[sta[i]].x-p1[sta[i+1]].x);
//求b、c到a的垂线的距离之和hb+hc=h2
hb=dist(p1[sta[bb]],a2,b2,c2),hc=dist(p1[sta[cc]],a2,b2,c2),h2=hb+hc;
//计算面积
if(h1*h2