小棕圈地 凸包旋转卡壳

小粽圈地

问题描述
小粽家里有一块地,地上有 n 个木桩。小粽家的地可以看作是一个平面,并且小粽知道每个木桩的坐标 (xi,yi)。
小粽很喜欢四边形,现在她想从这些木桩中选出 4 个来围成一个四边形(这个四边形为简单多边形,即每条边不能和自己相交,但不一定要为凸四边形),并使得这个四边形的面积最大。请你帮小粽算出这个最大值是多少。
输入格式

第一行一个正整数 n 表示木桩的大小。
接下来 n 行,第 i 行位两个实数 xi,yi,描述了第 i 个木桩的坐标。

输出格式

输出一行一个实数,表示围出的最大的四边形的面积。保留三位小数。

输入样例1

5
0 0
1 0
1 1
0 1
0.5 0.5

输出样例1

1.000

样例2
点此下载。

数据范围及约定
20% 的数据满足 n ≤100;
60% 的数据满足 n ≤400;
80% 的数据满足 n ≤1500;
100% 的数据满足 n ≤5000,所有坐标都在 int 范围内。
提示
[显然,答案是在凸包上的]
[可以考虑枚举一条对角线,再设法确定另外两点的位置,例如注意到点的位置具有单峰性。]
[更可考虑求对角线与凸包的切点,利用单调性均摊复杂度]

题解

//旋转卡壳法。

#include <vector>
#include <stdio.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;


struct Point {
	double x, y;
	Point(double x = 0, double y = 0) : x(x), y(y) {}

	void read()
	{
		scanf("%lf%lf", &x, &y);
	}

	void print()
	{
		printf("%lf %lf\n", x, y);
	}
};

Point operator + (const Point& a, const Point& b)
{
	return Point(a.x + b.x, a.y + b.y);
}

Point operator - (const Point& a, const Point& b)
{
	return Point(a.x - b.x, a.y - b.y);
}

double cross(Point a, Point b)
{
	return a.x * b.y - a.y * b.x;
}

bool cmp(const Point& a, const Point& b)
{
    return a.x==b.x ? a.y<b.y : a.x<b.x;
}

/* ============ 代码实现开始 ==========*/

// p, n: 传入点集及大小
// ch: 返回的凸包
// 返回值:凸包的大小
int getConvexhull(Point p[], int n, Point ch[])
{
    sort(p,p+n,cmp);
    
    int m=0;
    //求下凸壳
    for(int i=0; i<n; ++i){
        for(;m>1&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<0;--m) ;
        ch[m++]=p[i];
    }

    //求上凸壳
    int t=m;
    for(int i=n-2; i>=0; --i){
        for(;m>t&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<0;--m) ;
        ch[m++]=p[i];
    }
//    for(int i=0; i<m-1; i++)
//        printf("(%lf,%lf)\n",ch[i].x,ch[i].y);
    return m-1;
    //返回值为凸包内点的数目
}

// p, n: 传入的凸包及大小
// 返回最终答案
double solve(Point p[], int n)
{
    double ans = 0;
    
    for(int i=0; i<n; i++)
        p[i+n] = p[i];  //复制一份方便代码编写
    for(int i=0; i<n; i++){
        //int a=i,b=i+1;
        int a=1,b=1;
        //旋转卡壳法,以ij为对角线进行枚举
        for(int j=i+1; j<n; j++){
            while ( /*(a+1)%n!=j &&*/ cross(p[a+1]-p[i],p[j]-p[i])>cross(p[a]-p[i],p[j]-p[i]) )
                a++;
            while ( /*(b+1)%n!=i &&*/ cross(p[j]-p[i],p[b+1]-p[i])>cross(p[j]-p[i],p[b]-p[i]) )
                b++;
            
            ans = max(ans,cross(p[j]-p[i],p[b]-p[a]));
        }
    }
    return ans/2;
}

/* ============ 代码实现结束 ==========*/


#define maxn 5000

Point p[2 * maxn + 10], ch[2 * maxn + 10];

int main()
{

	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++)
		p[i].read();

	printf("%.3lf\n", solve(ch, getConvexhull(p, n, ch)));
	return 0;
}

上一篇:composer安装laravel


下一篇:论文解读:Detach and Adapt: Learning Cross-Domain Disentangled Deep Representation