2018.10.18【SCOI2007】【BZOJ1069】【洛谷P4166】最大土地面积(凸包)(旋转卡壳)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83147818

BZOJ传送门

洛谷传送门


解析:

首先,最大的土地面积选出来的四个点一定在凸包上。
如果不在,总是可以将一个点移动到凸包上使得面积更大,就不详细证明了。

于是先求凸包,简化问题,最朴素的做法就是枚举凸包上的四个点。
那么,我们得到了一个 O ( n 4 ) O(n^4) 优秀 做法。

考虑是不是其中每一个都必须要求出来?

显然不是,我们把所求的四边形转化一下变成三角形,枚举对角线分割,那么问题就变成了,求出当底边确定,顶点在凸包上的最大三角形面积。

旋转卡壳。维护两个指针分别表示上半部分的最大三角形面积和下半部分的最大三角形面积,每次固定对角线的一个端点, O ( n ) O(n) 移动另一个端点,同时调整上下指针的位置,更新答案。

显然,由于上下指针在一个端点固定而随着另一个端点移动的均摊复杂度是 O ( n ) O(n) ,总复杂度 O ( n 2 ) O(n^2)


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline double getdb(){
	re double x,y=1.0;
	re char c;
	re bool f=0;
	while(!isdigit(c=gc()))if(c=='-')f=1;x=c^48;
	while(isdigit(c=gc()))x=(x*10)+(c^48);
	if(c!='.')return f?-x:x;
	while(isdigit(c=gc()))x+=(y/=10)*(c^48);
	return f?-x:x;
}

cs double eps=1e-6;
cs int N=2003;
struct Point{
	double x,y;
	Point(cs double &_x=0,cs double &_y=0):x(_x),y(_y){}
	friend Point operator+(cs Point &a,cs Point &b){return Point(a.x+b.x,a.y+b.y);}
	friend Point operator-(cs Point &a,cs Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend double operator*(cs Point &a,cs Point &b){return a.x*b.y-b.x*a.y;}
	friend Point operator*(cs Point &a,cs double &b){return Point(a.x*b,a.y*b);}
	friend double dot(cs Point &a,cs Point &b){return a.x*b.x+a.y*b.y;}
	double norm()cs{return sqrt(dot(*this,*this));}
}p[N];

inline int sign(cs double &x){
	return fabs(x)<eps?0:(x>0?1:-1);
}

inline double trangle(cs Point &a,cs Point &b,cs Point &c){
	return fabs((a-b)*(b-c))/2;
}

inline bool cmp1(cs Point &a,cs Point &b){
	return a.x==b.x?a.y<b.y:a.x<b.x;
}

inline bool cmp2(cs Point &a,cs Point &b){
	return sign((a-p[1])*(b-p[1]))==0?(a-p[1]).norm()<(b-p[1]).norm():(a-p[1])*(b-p[1])>0;
}

int n;
inline void convex_hull(int m){
	sort(p+1,p+m+1,cmp1);
	sort(p+2,p+m+1,cmp2);
	n=1;
	for(int re i=2;i<=m;++i){
		while(n>=2&&sign((p[n]-p[n-1])*(p[i]-p[n-1]))<=0)--n;
		p[++n]=p[i];
	}
}

inline int nxt(int i){return i%n+1;}
inline int pre(int i){return i==1?n:i-1;}

double ans;
inline void solve(){
	for(int re i=1,u,d;i<=n;++i){
		u=i+1;
		d=i;
		for(int re j=i+1;j<=n;++j){
			while(trangle(p[j],p[i],p[nxt(u)])>trangle(p[j],p[i],p[u]))u=nxt(u);
			while(trangle(p[j],p[i],p[nxt(d)])>trangle(p[j],p[i],p[d]))d=nxt(d);
			ans=max(ans,trangle(p[j],p[i],p[u])+trangle(p[j],p[i],p[d]));
		}
	}
}

signed main(){
	scanf("%d",&n);
	for(int re i=1;i<=n;++i){
		p[i].x=getdb();
		p[i].y=getdb();
	}
	convex_hull(n);
	solve();
	printf("%.3f",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83147818