[P3187][HNOI2007]最小矩形覆盖(旋转卡壳)

用旋转卡壳做。先求出凸包,枚举每一条边作为矩形的一边。画画图可以看出另外三个点的决策应该是单调的。对面的点用叉乘看三角形面积大小判断,两边的点用点乘看向量在已固定的边上投影的长度(即矩形的宽)判断。注意第一次的两侧定点应分别从对面定点的两侧开始判断,需要赋初值。然后用点到直线距离,两直线交点等数学运算求一求就好了。具体看代码注释吧。最后需要避免因精度问题输出-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

 

你可能感兴趣的:(凸包,旋转卡壳)