bzoj 1185 [HNOI2007]最小矩形覆盖(坑)

毒瘤出题人...我真的做不动了
//bzoj 1185 [HNOI2007]最小矩形覆盖
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define eps 1e-8
#define inf 1e15
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=100005;
double ans=inf;
struct point {double x,y;} p[mxn],s[mxn],c[mxn];
int n,m,top;
inline double dis(point a,point b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline double cross(point p0,point p1,point p2)
{
	return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
inline bool comp(point a,point b)
{
	int tmp=cross(p[0],a,b);
	if(tmp>0 || (tmp<=eps && dis(p[0],a)>dis(p[0],b))) return 1;
	return 0;
}
inline void graham()
{
	int i,j;
	s[0]=p[0],s[1]=p[1],top=1;
	fo(i,2,n-1)
	{
		while(top && cross(s[top-1],s[top],p[i])<0) top--;
		s[++top]=p[i];
	}
	top++;
}
inline void rc()
{
	int i,j,q=1,a,b;
	fo(i,0,top-1)
	{
		double h,h1,h2,high,x1,y1,x2,y2,k;
		while(fabs(cross(s[(q+1)%top],s[(i+1)%top],s[i]))>fabs(cross(s[q],s[(i+1)%top],s[i])))
		  q=(q+1)%top;
		high=fabs(cross(s[q],s[(i+1)%top],s[i]))/dis(s[i],s[(i+1)%top]);
		if(i==0) a=2,b=(q+1)%top;
		x1=s[(i+1)%top].x-s[i].x,y1=s[(i+1)%top].y-s[i].y;
		x2=s[(a+1)%top].x-s[a].x,y2=s[(a+1)%top].y-s[a].y;
		while(x1*x2+y1*y2>=0)
		  a=(a+1)%top,x2=s[(a+1)%top].x-s[a].x,y2=s[(a+1)%top].y-s[a].y;
		x2=s[a].x-s[i].x,y2=s[a].y-s[i].y;
		h1=(x1*x2+y1*y2)/dis(s[i],s[(i+1)%top]);
		  
		x2=s[(b+1)%top].x-s[b].x,y2=s[(b+1)%top].y-s[b].y;
		while(x1*x2+y1*y2<=0)
		  b=(b+1)%top,x2=s[(b+1)%top].x-s[b].x,y2=s[(b+1)%top].y-s[b].y;
		x1=-x1,y1=-y1;
		x2=s[b].x-s[(i+1)%top].x,y2=s[b].y-s[(i+1)%top].y;
		h2=(x1*x2+y1*y2)/dis(s[i],s[(i+1)%top]);
		h=h1+h2-dis(s[i],s[(i+1)%top]);
		if(h*high<ans)
		{
			ans=h*high;
			x1=s[(i+1)%top].x-s[i].x,y1=s[(i+1)%top].y-s[i].y;
			k=h1/dis(s[i],s[(i+1)%top]);
			c[1]=(point){s[i].x+k*x1,s[i].y+k*y1};
			swap(x1,y1),x1=-x1;
			k=high/dis(s[i],s[(i+1)%top]);
			c[2]=(point){c[1].x+k*x1,c[1].y+k*y1};
			
			x1=-s[(i+1)%top].x+s[i].x,y1=-s[(i+1)%top].y+s[i].y;
			k=h2/dis(s[i],s[(i+1)%top]);
			c[3]=(point){s[(i+1)%top].x+k*x1,s[(i+1)%top].y+k*y1};
			swap(x1,y1),y1=-y1;
			k=high/dis(s[i],s[(i+1)%top]);
			c[4]=(point){c[3].x+k*x1,c[3].y+k*y1};
			
			swap(c[3],c[4]);
		}
	}
	printf("%.5lf\n",ans);
	double mn=c[1].y;
	int k=1;
	fo(i,2,4)
	  if(mn>c[i].y) mn=c[i].y,k=i;
	  else if(fabs(mn-c[i].y)<=eps && c[i].x<c[k].x) k=i;
	fo(i,0,3)
	{
		if(k+i<=4)
		  printf("%.5lf %.5lf\n",c[k+i].x,c[k+i].y);
		else 
		  printf("%.5lf %.5lf\n",c[k+i-4].x,c[k+i-4].y);
	}
}
int main()
{
	int i,j,u=0;
	scanf("%d",&n);
	fo(i,0,n-1)
	  scanf("%lf%lf",&p[i].x,&p[i].y);
	fo(i,1,n-1)
	  if(p[u].y>p[i].y || (p[u].y-p[i].y)<=eps && p[u].x>p[i].x)
	    u=i;
	swap(p[0],p[u]);
	sort(p+1,p+n,comp);
	graham(),rc();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值