Bzoj1185 [HNOI2007]最小矩形覆盖 + Bzoj1069 [SCOI2007]最大土地面积

134 篇文章 0 订阅
105 篇文章 0 订阅

.
题目链接1
题目链接2
2道旋转卡壳算法+凸包模板题
应该说是一个比较标准的算法了,凸包就是排序+单调栈搞一下就好
旋转卡壳就是一个运用了凸包单调性的思想,每次逆时针走一条边,就把对点移动一个
第一题稍微麻烦,需要枚举矩形的一条边,让后找水平方向和垂直方向最远距离,分别用点积和叉积就可以判
第二题直接枚举对角线,让后找左右点到直线最长距离
稍微注意基本运算和函数的实现就可以了,剩下的都是可以现推的
(下一篇半平面交)

//bzoj1185
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define eps 1e-7
using namespace std;
struct vec{
	db x,y;
	vec(){}
	vec(db a,db b){ x=a; y=b; }
}; typedef vec point;
inline bool cx(vec a,vec b){ return a.x==b.x?a.y<b.y:a.x<b.x; }

inline int sgn(db x){ return fabs(x)<eps?0:(x>0?1:-1); }

inline db dot(vec a,vec b){ return a.x*b.x+a.y*b.y; }
inline db crs(vec a,vec b){ return a.x*b.y-a.y*b.x; }

inline db len(vec a){ return sqrt(dot(a,a)); }

inline vec operator+(vec a,vec b){ return (vec){a.x+b.x,a.y+b.y}; }
inline vec operator-(vec a,vec b){ return (vec){a.x-b.x,a.y-b.y}; }

inline vec operator*(vec a,db  x){ return (vec){a.x*x,a.y*x}; }
inline vec operator/(vec a,db  x){ return (vec){a.x/x,a.y/x}; }

inline db dis(point p,point a,point b){
	return fabs(crs(p-a,a-b)/len(a-b));
}
inline point glp(point a,point A,point b,point B){
	vec u=a-b;
	db t=crs(B-b,u)/crs(A-a,B-b);
	return a+(A-a)*t;
}
point s[200010],q[200010]; int n,m,t;
inline db disr(point a,point b,point c){
	return dot(b-a,c-a);
}
inline db disl(point a,point b,point c){
	return dot(a-b,c-a);
}
inline db disu(point a,point b,point c){
	return fabs(crs(c-a,a-b));
}
inline db calS(int i,int j,int l,int r){
	vec c=s[i+1]-s[i];
	return dis(s[j],s[i],s[i+1])*dot(c,s[r]-s[l])/len(c);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%lf %lf",&s[i].x,&s[i].y);
	sort(s+1,s+1+n,cx);
	for(int i=1;i<=n;++i){
		while(1<t && sgn(crs(q[t]-q[t-1],s[i]-q[t-1]))<=0) --t;
		q[++t]=s[i];
	}
	m=t;
	for(int i=n-1;i;--i){
		while(m<t && sgn(crs(q[t]-q[t-1],s[i]-q[t-1]))<=0) --t;
		q[++t]=s[i];
	}
	--t;
	memcpy(s+1,q+1,t*sizeof(vec));
	memcpy(s+1+t,q+1,t*sizeof(vec));
	memcpy(s+1+t+t,q+1,t*sizeof(vec));
	int l,r,j,i=1;
	for(r=3;disr(s[i],s[i+1],s[r])<disr(s[i],s[i+1],s[r+1]);++r);
	for(l=t;disl(s[i],s[i+1],s[l])<disl(s[i],s[i+1],s[l-1]);--l);
	for(j=3;disu(s[i],s[i+1],s[j])<disu(s[i],s[i+1],s[j+1]);++j);
	db A=0,B; int ai,aj,al,ar;
	A=calS(i,j,l,r); ai=i; al=l; ar=r; aj=j;
	for(i=2;i<=t;++i){
		for(;disr(s[i],s[i+1],s[r])<disr(s[i],s[i+1],s[r+1]);++r);
		for(;disl(s[i],s[i+1],s[l])<disl(s[i],s[i+1],s[l+1]);++l);
		for(;disu(s[i],s[i+1],s[j])<disu(s[i],s[i+1],s[j+1]);++j);
		B=calS(i,j,l,r);
		if(A>B){ A=B; ai=i; al=l; ar=r; aj=j; }
	}
	vec v=s[ai]-s[ai+1],t(v.y,-v.x);
	point a[8];
	a[4]=a[0]=glp(s[ai],s[ai+1],s[ar],s[ar]+t);
	a[7]=a[3]=glp(s[ai],s[ai+1],s[al],s[al]+t);
	a[5]=a[1]=glp(s[aj],s[aj]+v,s[ar],s[ar]+t);
	a[6]=a[2]=glp(s[aj],s[aj]+v,s[al],s[al]+t);	
	int p=0;
	for(int i=1;i<4;++i) if(sgn(a[i].y-a[p].y)<0) p=i;
		else if(!sgn(a[i].y-a[p].y) && sgn(a[i].x-a[p].x)<=0) p=i;
	printf("%.5lf\n",A);
	for(int i=0;i<4;++i) printf("%.5lf %.5lf\n",fabs(a[p+i].x),fabs(a[p+i].y));
}
//Bzoj1069:
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define db double
#define eps 1e-7
using namespace std;
struct vec{ db x,y; }; typedef vec point;
inline bool cx(vec a,vec b){ return a.x==b.x?a.y<b.y:a.x<b.x; }
inline int sgn(db x){ return fabs(x)<eps?0:(x>0?1:-1); }
inline db dot(vec a,vec b){ return a.x*b.x+a.y*b.y; }
inline db crs(vec a,vec b){ return a.x*b.y-a.y*b.x; }
inline db len(vec a){ return sqrt(dot(a,a)); }

inline vec operator+(vec a,vec b){ return (vec){a.x+b.x,a.y+b.y}; }
inline vec operator-(vec a,vec b){ return (vec){a.x-b.x,a.y-b.y}; }
inline vec operator*(vec a,db  x){ return (vec){a.x*x,a.y*x}; }
inline vec operator/(vec a,db  x){ return (vec){a.x/x,a.y/x}; }

inline db dis(point p,point a,point b){
	db c=crs(p-a,a-b);
	return fabs(c/len(a-b));
}
int n,m,t; point s[2010],q[2010]; db l[2010],r[2010],A;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%lf%lf",&s[i].x,&s[i].y);
	sort(s+1,s+1+n,cx);
	for(int i=1;i<=n;++i){
		while(t>1 && sgn(crs(q[t]-q[t-1],s[i]-q[t-1]))<=0) --t;
		q[++t]=s[i];
	}
	m=t;
	for(int i=n-1;i;--i){
		while(t>m && sgn(crs(q[t]-q[t-1],s[i]-q[t-1]))<=0) --t;
		q[++t]=s[i];
	}
	--t;
	memcpy(s+1,q+1,t*sizeof(vec));
	for(int i=1;i<=t;++i){
		int j=i+2,k=i+1;
		for(;j<t;++j){
			while(dis(s[k],s[i],s[j])<=dis(s[k+1],s[i],s[j])) ++k;
			l[j]=dis(s[k],s[i],s[j]);
		}
		j=t-1; k=t;
		for(;j>i+1;--j){
			while(dis(s[k],s[i],s[j])<=dis(s[k-1],s[i],s[j])) --k;
			r[j]=dis(s[k],s[i],s[j]);
		}
		for(j=i+1;j<t;++j)	
			A=max(A,len(s[i]-s[j])*(l[j]+r[j]));
	}
	printf("%.3lf\n",A/2.);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值