小粽圈地
问题描述
小粽家里有一块地,地上有 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;
}