• 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());
    }
    
  • 相关阅读:
    套接字socket
    Windows环境下教你用Eclipse ADT 插件生成.h/.so文件,Java下调用JNI,轻松学习JNI
    How to start/stop DB instance of Oracle under Linux
    Oracle SGA具体解释
    Oracle Study之--Oracle 单实例11.2.0.1.0升级到11.2.0.3.0
    MapReduce(十六): 写数据到HDFS的源代码分析
    Spring表达式语言SpEL简单介绍
    LinkCutTree详解
    洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)
    树链剖分详解
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6430714.html
Copyright © 2020-2023  润新知