题目

给定\(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. python中将datetime对象转化为时间戳

    从mongodb中读取出来的记录中,时间存储在datetime对象里,返回给客户端的却要求是时间戳格式,因此需要将对应的datetime时间转化为时间戳,从stackoverflow上找到同样的问题和 ...

  2. SQl 语句 表的连接

    当涉及到多个表查询时就需要使用将表连接的方法进行查询. SQL语句连接的方式根本上分为5种: •EQUI JOIN •SEMI JOIN 3 •ANTI JOIN 4 •CROSS JOIN •DIV ...

  3. JavaScript事件及BOM和DOM

    1. 事件 1.1 事件绑定 # 写在html元素中<button onclick="code..."></div>​# 把事件当做元素对象的方法btnEl ...

  4. Linux命令应用大词典-第8章 日期和时间

    8.1 cal:显示日历信息 8.2 date:显示和设置系统日期和时间 8.3 hwclock:查看和设置硬件时钟 8.4 clock:查看和设置硬件时钟 8.5 clockdiff:主机之间测量时 ...

  5. 初学Direct X(8) ——碰撞检测

    初学Direct X(8) --碰撞检测 真正让一个游戏鹤立鸡群的是程序对碰撞的响应有多好,这里介绍两种检测的方法: 1) 基于边框的碰撞检测 2) 基于距离的碰撞检测 1. 基于边框的碰撞检测 1. ...

  6. NO.01---今天聊聊Vuex的简单入门

    作为一款个人认为非常牛x的框架,个人使用起来得心应手,所以近期就记录一下这款框架吧. 首先说一说 Vuex 是什么? 官方给出的解释:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它 ...

  7. 【带 josn参数的测法】

    遇到json 参数的情况这样写  ,否则就会报错 cod 415   nocookie post请求 ,","email":"beihe@163.com&quo ...

  8. python3 bytes与hex_string之间的转换

    1, bytes to hex_string的转换: def byte_to_hex(bins): """ Convert a byte string to it's h ...

  9. codeforces 359E Neatness(DFS+构造)

    Simon loves neatness. So before he goes to bed, Simon wants to complete all chores in the house. Sim ...

  10. mysql mariadb 密码设置

    原文:https://my.oschina.net/uyunsky/blog/109532 一.初始安装 Method 1:在/usr/local/mysql/bin/下:./mysqladmin - ...