BZOJ1069 [SCOI2007] 最大土地面积

@(BZOJ)[凸包, 旋轉卡殼]

Description

在某块平面土地上有\(N\)个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成
的多边形面积最大。

Input

第1行一个正整数\(N\),接下来\(N\)行,每行\(2\)个数\(x\),\(y\),表示该点的横坐标和纵坐标。

Output

最大的多边形面积,答案精确到小数点后\(3\)位。

Sample Input

5
0 0
1 0
1 1
0 1
0.5 0.5

Sample Output

1.000

HINT

数据范围 \(n<=2000\), $ |x|, |y|<=100000$

Solution

模板題
主要用於學習Graham掃描法求凸包, 叉積判斷向量的關係以及叉積計算三角形面積.
至於所謂的旋轉卡殼做法, 在這一題上實際上體現得並不深刻. 可以作為一個初步的理解吧.

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

const int N = 1 << 11;
const double INF = 1e30;

int n;

struct point
{
	double x, y;
	
	point(){}
	
	inline point(double _x, double _y)
	{
		x = _x, y = _y;
	}
	
	inline friend int operator <(const point &a, const point &b)
	{
		return a.x == b.x ? a.y < b.y : a.x < a.y;
	}
	
	inline friend point operator -(const point &a, point &b)
	{
		return point(a.x - b.x, a.y - b.y);
	}
}a[N];

point orig;

inline double det(point a, point b)
{
	return a.x * b.y - a.y * b.x;
}

inline int cmp(point a, point b)
{
	return det(a - orig, b - orig) > 0;
}

int top;
point stack[N];

inline void graham()	//求凸包
{
	int p = 0;
	
	for(int i = 1; i < n; i ++)
		if(a[i] < a[p])
			p = i;

	swap(a[0], a[p]);
	orig = a[0];
	sort(a + 1, a + n, cmp);
	
	top = 0;
	stack[top ++] = a[0], stack[top ++] = a[1];
	
	for(int i = 2; i < n; i ++)
	{
		while(top && det(stack[top - 1] - stack[top - 2], a[i] - stack[top - 1]) <= 0)
			top --;
			
		stack[top ++] = a[i];
	}
}

inline double getArea(point a, point b, point c)
{
	return fabs(det(a - c, b - c) / 2);
}

inline double solve()	//旋轉卡殼, 利用的是凸包的單調性.
{
	double ans = - INF;
	
	for(int i = 0; i < top; i ++) //枚舉一條對邊
	{
		int a = i % top, b = (i + 2) % top; //發現另一條對邊的端點具有單調性
		
		for(int j = i + 2; j < top; j ++)
		{
			while((a + 1) % top != j && getArea(stack[i], stack[j], stack[a]) < getArea(stack[i], stack[j], stack[(a + 1) % top]))
				a = (a + 1) % top;
				 
			while((b + 1) % top != i && getArea(stack[i], stack[j], stack[b]) < getArea(stack[i], stack[j], stack[(b + 1) % top]))
				b = (b + 1) % top;
				
			ans = max(ans, getArea(stack[i], stack[j], stack[a]) + getArea(stack[i], stack[j], stack[b]));
		}
	}
	
	return ans;
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("BZOJ1069.in", "r", stdin);
	freopen("BZOJ1069.out", "w", stdout);
	#endif
	
	scanf("%d", &n);
	
	for(int i = 0; i < n; i ++)
		scanf("%lf%lf", &a[i].x, &a[i].y);
		
	graham();
	printf("%.3lf", solve());
}
posted @ 2017-02-22 20:04  Zeonfai  阅读(195)  评论(0编辑  收藏  举报