题目

给定\(n\ (n\le 2000)\)个坐标,求四个坐标使得围起来的四边形面积最大。

分析

最暴力的想法是枚举四个点,然而肯定超时。接着不知道怎么想到中途相遇,然而一点关系都没有。这里用到了一个单调性:

如果在凸包上确定了一个点\(x\),令\(x\)逆时针方向的第一个点为\(y\),这时确定了一个点\(z\)使得\(S_{\triangle XYZ}最大,那么当\)y\(逆时针移动的时候,使得三角形面积最大的点\)z\(就会不动或逆时针移动。这个性质发展成为我们说的旋转卡壳。
这就是说,如果在凸包上确定了一个点,那么我们可以\)O(n)\(求出包含这个点的所有凸包上的四边形的最大面积。
所以我们可以枚举所有点,在\)O(n^2)$中求出答案。

代码

这里有几个地方需要注意到。

  1. 求凸包极角排序的时候,选择的基础点一定是最下面,最左边的,而不可以仅仅是最下面的,否则会出现\(0\)和\(-0\)这种情况。
  2. 在求凸包单调栈弹出的时候,要用小于等于号,否则如果有重点的情况就会出现问题。
  3. 在计算答案时,每次移动\(j\)的时候要记得更新\(s1\)和\(s2\)。
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=2e3+10;
struct node {
double x,y;
} a[maxn],sta[maxn];
int top=0;
double P(double x) {
return x*x;
}
double dis(node a,node b) {
return sqrt(P(a.x-b.x)+P(a.y-b.y));
}
double cross(node a,node b,node c) {
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool cmp(node e,node f) {
double tmp=cross(a[1],e,f);
if (tmp>0) return true;
if (tmp<0) return false;
return dis(a[1],e)<dis(a[1],f);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
int n;
scanf("%d",&n);
for (int i=1;i<=n;++i) {
scanf("%lf%lf",&a[i].x,&a[i].y);
if (a[i].y<a[1].y || (a[i].y==a[1].y && a[i].x<a[1].x)) swap(a[1],a[i]); // here
}
sort(a+2,a+n+1,cmp);
sta[top=1]=a[1];
for (int i=2;i<=n;++i) {
while (top>1 && cross(sta[top-1],sta[top],a[i])<=0) --top; // here
sta[++top]=a[i];
}
if (top<=4) {
double ans=0;
if (top>2) ans=cross(sta[1],sta[2],sta[3]);
if (top==4) ans+=cross(sta[1],sta[3],sta[4]);
ans/=2;
printf("%.3lf\n",ans);
return 0;
}
double ans=0;
for (int i=1;i<=top-2;++i) {
int j=(i+1)%top+1,k=i%top+1,l,id=j%top+1;
double s1=cross(sta[i],sta[k],sta[j])/2;
double s2=0;
for (l=id;l!=i;l=l%top+1) {
double tmp=cross(sta[i],sta[j],sta[l])/2;
if (tmp>s2) s2=tmp,id=l;
}
l=id;
ans=max(ans,s1+s2);
for (j=j%top+1;j%top+1!=i;j=j%top+1) {
s1=cross(sta[i],sta[k],sta[j])/2; // here
s2=cross(sta[i],sta[j],sta[l])/2; // here
if (l==j) l=l%top+1,s2=cross(sta[i],sta[j],sta[l])/2;
while (k%top+1!=j && cross(sta[i],sta[k%top+1],sta[j])/2>s1) k=k%top+1,s1=cross(sta[i],sta[k],sta[j])/2;
while (l%top+1!=i && cross(sta[i],sta[j],sta[l%top+1])/2>s2) l=l%top+1,s2=cross(sta[i],sta[j],sta[l])/2;
ans=max(ans,s1+s2);
}
}
printf("%.3lf\n",ans);
}

bzoj1069-最大土地面积的更多相关文章

  1. 【BZOJ-1069】最大土地面积 计算几何 + 凸包 + 旋转卡壳

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 2707  Solved: 1053[Submit][Sta ...

  2. bzoj1069 SCOI2007 最大土地面积

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 2560  Solved: 983 Description ...

  3. bzoj1069 [SCOI2007]最大土地面积 旋转卡壳

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3767  Solved: 1501[Submit][Sta ...

  4. BZOJ1069 SCOI2007最大土地面积(凸包+旋转卡壳)

    求出凸包,显然四个点在凸包上.考虑枚举某点,再移动另一点作为对角线,容易发现剩下两点的最优位置是单调的.过程类似旋转卡壳. #include<iostream> #include<c ...

  5. BZOJ1069 [SCOI2007]最大土地面积 【凸包 + 旋转卡壳】

    题目链接 BZOJ1069 题解 首先四个点一定在凸包上 我们枚举对角线,剩下两个点分别是两侧最远的点 可以三分,复杂度\(O(n^2logn)\) 可以借鉴旋转卡壳的思想,那两个点随着对角线的一定单 ...

  6. [BZOJ1069][SCOI2007]最大土地面积(水平扫描法求凸包+旋转卡壳)

    题意:在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成. 的多边形面积最大.n<=2000. 先求凸包,再枚举对角线,随着对角线的斜率上升,另外两 ...

  7. [BZOJ1069][SCOI2007]最大土地面积 凸包+旋转卡壳

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3669  Solved: 1451[Submit][Sta ...

  8. [Bzoj1069][Scoi2007]最大土地面积(凸包)(旋转卡壳)

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3629  Solved: 1432[Submit][Sta ...

  9. BZOJ1069 SCOI2007 最大土地面积 凸包、旋转卡壳

    传送门 在这里假设可以选择两个相同的点吧-- 那么选出来的四个点一定会在凸包上 建立凸包,然后枚举这个四边形的对角线.策略是先枚举对角线上的一个点,然后沿着凸包枚举另一个点.在枚举另一个点的过程中可以 ...

  10. 【bzoj1069】最大土地面积

    Description 在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大. Input 第1行一个正整数N,接下来N行,每行2个数x,y ...

随机推荐

  1. crontab执行PHP

    在stackoverflow上看到一个问题:http://stackoverflow.com/questions/14015543/crontab-php-wget-or-curl 有三种通过cron ...

  2. SpringBoot入门(二)——起步依赖

    本文来自网易云社区 在前一篇我们通过简单几步操作就生成了一个可以直接运行的Web程序,这是因为SpringBoot代替我们做了许多工作,概括来讲可以分为起步依赖和自动配置.这一篇先来看看起步依赖. 项 ...

  3. mysql索引 b+树

    1.B+树基本概念 B+树的语言定义比较复杂,简单的说是为磁盘存取设计的平衡二叉树 网上经典图,黄色p1 p2 p3代表指针,蓝色的代表磁盘,里面包含数据项,第一层17,35,p1就代表小于17的,p ...

  4. hdu5698瞬间移动(杨辉三角+快速幂+逆元)

    瞬间移动 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...

  5. 第六模块:WEB框架开发 第1章·Django框架开发50~87

    51-表关系之一对多 52-表关系之多对多 53-表关系之一对一 54-数据库表关系之关联字段与外键约束 55-数据库表关系之sql创建关联表 56-ORM生成关联表模型 57-多表操作之一对多添加记 ...

  6. 【hidden】微信小程序hidden属性使用示例

    hidden属性用于隐藏标签,代码示例: <view hidden="{{!statusTag}}">我出来了~</view> <button bin ...

  7. 373. Partition Array by Odd and Even【LintCode java】

    Description Partition an integers array into odd number first and even number second. Example Given  ...

  8. token接口的测法

    接口一般都有权限的校验,一般是需要登录后才可以调用 对于接口的认证,一般通过两种方式来实现1.校验用户请求中是否包含某项指定的cookie2.校验用户的请求的header中是否包含某项指定的字段(to ...

  9. JAVA基础学习之路(五)数组的定义及使用

    什么是数组:就是一堆相同类型的数据放一堆(一组相关变量的集合) 定义语法: 1.声明并开辟数组 数据类型 数组名[] = new 数据类型[长度]: 2.分布完成 声明数组:数据类型 数组名 [] = ...

  10. (原) MaterialEditor部- UmateriaEditor中 Node编译过程和使用(3)

    @author: 白袍小道 转载说明原处 插件同步在GITHUB: DaoZhang_XDZ         说明 1.本篇是接着-----(原) MaterialEditor部- UmateriaE ...