bzoj1185[HNOI2007]最小矩形覆盖

啊啊啊啊啊啊啊啊手速不行啊打了好久啊好吧其实也想了好久

这道题真是神奇WA了好几次= =结果还是因为看错题

我们可以做个凸包,然后这个矩形上一定有点,而且不止一个,所以只有一个点的一定不是最优的,这样的话我们就可以枚举一个凸包上面的点(因为点太多23333333不然我就枚举对角线了),然后我们可以用叉积来卡这个点对面的点,用点积来卡两边的店,这样我们就可以用旋转卡壳来完美卡住这个矩形

至于输出,真的好麻烦愣是调了40分钟

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iomanip>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
#define N 50005
#define eps 1e-8
struct dian
{
	double x,y;
}d[N],ch[N],ans[5];
double ansarea=0.0;
int n;

double cross(dian a,dian b,dian c)
{
	dian xlab,xlac;
	xlab.x=b.x-a.x;
	xlab.y=b.y-a.y;
	xlac.x=c.x-a.x;
	xlac.y=c.y-a.y;
	return (xlab.x*xlac.y)-(xlac.x*xlab.y);
}

double dj(dian a,dian b,dian c)
{
	dian xlab,xlac;
	xlab.x=b.x-a.x;
	xlab.y=b.y-a.y;
	xlac.x=c.x-a.x;
	xlac.y=c.y-a.y;
	return (xlab.x*xlac.x)+(xlab.y*xlac.y);
}

double dis(dian a,dian b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool sortcom(dian a,dian b)
{
	double t=cross(d[1],a,b);
	if (fabs(t)<eps) return dis(d[1],a)-dis(d[1],b)<eps;
	return t>0;
}
	
bool xy(dian a,dian b)
{
	if (fabs(a.x-b.x)<=eps) return (a.y-b.y<eps);
	else return (a.x-b.x<eps);
}

bool yx(dian a,dian b)
{
	if (fabs(a.y-b.y)<eps) return (a.x-b.x<eps);
	else return (a.y-b.y<eps);
}

dian add(dian a,dian b)
{
	dian t;
	t.x=a.x+b.x;
	t.y=a.y+b.y;
	return t;
}

dian minu(dian a,dian b)
{
	dian t;
	t.x=a.x-b.x;
	t.y=a.y-b.y;
	return t;
}

dian dcheng(dian a,double b)
{
	dian t;
	t.x=a.x*b;
	t.y=a.y*b;
	return t;
}

int s[N],top=0;
void graham()
{
	fo(i,2,n)
	if(yx(d[i],d[1])) swap(d[i],d[1]);
	sort(d+2,d+n+1,sortcom);
	s[++top]=1;
	fo(i,2,n)
	{
		while (top>1&&cross(d[s[top-1]],d[s[top]],d[i])<eps)top--;
		s[++top]=i;
	}
	s[0]=s[top];
	fo(i,0,top) ch[i]=d[s[i]];
//	cout<<top<<endl;
//	fo(i,1,top) cout<<ch[i].x<<' '<<ch[i].y<<endl;
}

//int q[5];
void getans(int i,int l,int up,int r)
{
	double D,H,L,R,B,S;
	D=dis(ch[i],ch[i+1]);
	L=dj(ch[i],ch[i+1],ch[l])/D;
	R=dj(ch[i],ch[i+1],ch[r])/D;
//	B=(L+R)-D;
	B=R-L;
	H=fabs(cross(ch[i],ch[i+1],ch[up]))/D;
	S=H*B;
//	cout<<i<<' '<<l<<' '<<up<<' '<<r<<' '<<L<<' '<<R<<' '<<S<<' '<<ansarea<<endl;
	if (S-ansarea<eps||fabs(ansarea)<eps)
	{
		ans[0]=add(ch[i],dcheng(minu(ch[i+1],ch[i]),(R/D)));
		ans[1]=add(ans[0],dcheng(minu(ch[r],ans[0]),(H/dis(ans[0],ch[r]))));
		ans[2]=minu(ans[1],dcheng(minu(ans[0],ch[i]),((R-L)/dis(ch[i],ans[0]))));
		ans[3]=minu(ans[2],minu(ans[1],ans[0]));
		ansarea=S;
	}
}

void RC()
{
	int up=1,l=1,r=1;
	fo(i,0,top-1)
	{
		while(cross(ch[i],ch[i+1],ch[up+1])-cross(ch[i],ch[i+1],ch[up])>-eps)
			up=(up+1)%top;
		while(dj(ch[i],ch[i+1],ch[r+1])-dj(ch[i],ch[i+1],ch[r])>-eps)
			r=(r+1)%top;
		if (i==0) l=r;
		while(dj(ch[i],ch[i+1],ch[l+1])-dj(ch[i],ch[i+1],ch[l])<eps)
			l=(l+1)%top;
		getans(i,l,up,r);
	}
}

int main()
{
//	freopen("data.in","r",stdin);
	scanf("%d",&n);
	fo(i,1,n) scanf("%lf%lf",&d[i].x,&d[i].y);
	graham();
	RC();
	int st=0;dian mi=ans[0];
	fo(i,1,3)
	if (yx(ans[i],mi)) st=i;
	cout<<setiosflags(ios::fixed);
    cout.precision(5);
    cout<<ansarea<<endl;
	fo(i,st,st+4)
	if (i%5==4) continue; 
	else cout<<ans[i%5].x<<' '<<ans[i%5].y<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值