L3-021 神坛 (30 分)

在古老的迈瑞城,巍然屹立着 n 块神石。长老们商议,选取 3 块神石围成一个神坛。因为神坛的能量强度与它的面积成反比,因此神坛的面积越小越好。特殊地,如果有两块神石坐标相同,或者三块神石共线,神坛的面积为 0.000

长老们发现这个问题没有那么简单,于是委托你编程解决这个难题。

输入格式:

输入在第一行给出一个正整数 n(3 ≤ n ≤ 5000)。随后 n 行,每行有两个整数,分别表示神石的横坐标、纵坐标(−10​9​​≤ 横坐标、纵坐标 <10​9​​)。

输出格式:

在一行中输出神坛的最小面积,四舍五入保留 3 位小数。

输入样例:

8
3 4
2 4
1 1
4 1
0 3
3 0
1 3
4 2

输出样例:

0.500

样例解释

输出的数值等于图中红色或紫色框线的三角形的面积

解题思路

我想说明的是,这个解题思路是怎么从暴力遍历里面脱胎出来的。请首先注意比对暴力法的代码和排序法的代码。

暴力遍历的思路是以每个点为中心(i),遍历其他的点(j,k),找到最小的面积,这个时间复杂度是O(n3)。在此基础上,直观想法就是改进成O(n2logn)(或者O(nm), m<3)。改进成对数复杂度的要点就是使用排序代替双重循环,或者使用二分查找,这里显然是前者。这就提炼出这道题的中心思想:用快速排序+线性遍历代替二重循环

然后就是如何设计排序算法了。计算三角形面积的公式是area = x1y2 - x2y1,通过这个公式发现了这个排序。按照这个三角形面积公式设计的cmp排序,可以保证最小的三角形由相邻的两个点构成。这个排序确实很抽象,因为不是基于一个绝对数值在排序,而是基于一个奇怪的比较方法,乍一看不能看出来上述的两点性质。

  • UPDATE
  • 三角形必须通过相邻的点构成,这一点存疑。我觉得需要证明cmp函数的传递性以及跨点的面积值确实大于相邻点,但这个命题不成立。保证找到最小三角形的implementation实际上是每个点轮流做中心的过程,但是不知道怎么证明正确性。
  • 事实上,这个算法果然是错的,blog给出了一个错误用例。但是思想可以借鉴。
    正确的做法应该用凸包

如果觉得上述过程太抽象,应该指出,上述过程中的排序其实具有几何意义,也就是极坐标角的大小。网上的那些博客大多都指出了这一点,但没有发现这道题背后的精髓其实是找到了一个合适的排列那些点的方法。(虽然如果没有这个几何对应,也不能设计出这个排序。)

最后注意一下数据范围的问题,点坐标本身数据范围没有超过int,但是涉及到计算坐标值的乘积,所以用int还是会溢出,所以long long。

代码

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdio>
#include <bitset>
using namespace std;const int N = 5000 + 5;struct point{// 本身数据范围没有超过int,但是涉及到计算xy元素的乘积,所以用int还是会溢出,所以ll。long long x;long long y;
};bool cmp(point p1, point p2){// 极坐标角较小的排在前面return p2.y * p1.x > p1.y * p2.x;
}point p[N], temp[N];
int n;
double ans = 1e18;int main(){// inputscanf("%d", &n);for(int i=0; i<n; i++){scanf("%lld %lld", &p[i].x, &p[i].y);}// 拿每个点做中心for(int i=0; i<n; i++){// 计算其他点的相对坐标,注意去掉下标为i的中心点int tmp_j = 0;for(int j=0; j<n; j++){if(i!=j){temp[tmp_j].x = p[j].x - p[i].x;temp[tmp_j].y = p[j].y - p[i].y;tmp_j++;}}// 按照面积公式单元排序sort(temp, temp+tmp_j, cmp);// 计算邻居三角形的面积并更新最小面积for(int j=0; j<tmp_j - 1; j++){double area = (temp[j].x*temp[j+1].y-temp[j+1].x*temp[j].y)*0.5;if(area < ans) ans = area;}}printf("%.3f", ans);return 0;
}

给出一个O(n3)的方法作对比,体会用快速排序代替二重循环的精髓,体会这个排序究竟起到了什么作用。

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdio>
#include <bitset>
using namespace std;const int N = 5000 + 5;struct point{// 本身数据范围没有超过int,但是涉及到计算xy元素的乘积,所以用int还是会溢出,所以ll。long long x;long long y;
};bool cmp(point p1, point p2){// 极坐标角较小的排在前面return p2.y * p1.x > p1.y * p2.x;
}point p[N], temp[N];
int n;
double ans = 1e18;int main(){// inputscanf("%d", &n);for(int i=0; i<n; i++){scanf("%lld %lld", &p[i].x, &p[i].y);}// 拿每个点做中心for(int i=0; i<n; i++){// 计算其他点的相对坐标,注意去掉下标为i的中心点int tmp_j = 0;for(int j=0; j<n; j++){if(i!=j){temp[tmp_j].x = p[j].x - p[i].x;temp[tmp_j].y = p[j].y - p[i].y;tmp_j++;}}// 计算邻居三角形的面积并更新最小面积for(int j=0; j<tmp_j - 1; j++){for(int k=0; k<j; k++){double area = (temp[j].x*temp[k].y-temp[k].x*temp[j].y)*0.5;if(area < ans && area > 1e-4) ans = area;}}}printf("%.3f", ans);return 0;
}

OJ:L3-021 神坛 伪解 排序后遍历相关推荐

  1. 详解【java实现】编写一个程序,从键盘读入一段英文(多行),找出其中所有的英文单词,统计每个单词出现的次数,并按照单词出现次数由大到小排序后输出。

    题目: 编写一个程序,从键盘读入一段英文(多行),找出其中所有的英文单词,统计每个单词出现的次数,并按照单词出现次数由大到小排序后输出. 前言: "统计每个单词出现的次数,并且按照由大到小排 ...

  2. 有道算法题--排序之桶排序实现求排序后相邻最大差值问题

    前言 一直误以为写文章太耗费费时间,昨日为尊敬高贵帅气逼人的导师所一语惊醒(未一鸣惊人之日,绝不提尊师名讳,嗯,没错),分享才是程序员最快的提升: 今天开始,做不到多写多练,就不是诚实善良的南方小菜啦 ...

  3. 1.8 Collections类操作集合详解——排序,查找,复制

    Collections类操作集合详解 Collections 类是 Java 提供的一个操作 Set.List 和 Map 等集合的工具类. Collections 类提供了许多操作集合的静态方法,借 ...

  4. C# dgv自动排序后,各种样式设定无效的解决办法

    C# dgv自动排序后,各种样式设定无效的解决办法 在网上搜索一些资料还是解决不了,所以自己写了记录一下: 给dgv添加一个sorted事件,每次点击小三角排序时就会调用这个方法,在这里将样式重新设定 ...

  5. Mysql高手系列 - 第8篇:详解排序和分页(order by limit),及存在的坑

    这是Mysql系列第8篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符号分开的表示可选其一. 本章内容 详解排序查询 详解limit limit存在的坑 分 ...

  6. Mysql系列 - 第八篇 :详解排序和分页(order by limit),及存在的坑

    这是Mysql系列第7篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符号分开的表示可选其一. 本章内容 详解排序查询 详解limit limit存在的坑 分 ...

  7. 玩转Mysql系列 - 第8篇:详解排序和分页(order by limit),及存在的坑

    打算提升sql技能的,可以加我微信itsoku,带你成为sql高手. 这是Mysql系列第8篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符号分开的表示可选 ...

  8. 一中OJ #1151 [USACO Jan08] 化妆晚会 | 排序与查找 | 解题报告

    一中OJ | #1151 化妆晚会 时限 1000MS/Case 内存 64MB/Case 题目描述 万圣节又到了!FJ打算带他的奶牛去参加一个化装晚会,但是FJ只做了一套能容下两头总长不超过 S 的 ...

  9. Python3 网络爬虫,获取全部省会城市(含直辖市)当前的气温,按当前气温从高到低排序后输出。

    Python3 网络爬虫,获取全部省会城市(含直辖市)当前的气温,按当前气温从高到低排序后输出. 网络编程技术实验二 实验内容: 用python client编写一个网络爬虫,获取全部省会城市(含直辖 ...

最新文章

  1. Redis 入门安装(Linux)
  2. char怎么比较_C语言的 main 函数到底怎么写才是对的?
  3. Win7 MongoDB可视化工具Robo 3T 1.2.1(robomongo)的安装使用
  4. Go报错:more than one character in rune literal
  5. linux内核亲和性,Linux中CPU亲和性(go)
  6. asp中chr()函数及转义符对照表
  7. 如何使用FM RH_STRUC_GET获得user assign的Organization unit
  8. “约见”面试官系列之常见面试题第二十二篇之函数闭包(建议收藏)
  9. 学习基础和C语言基础调查
  10. geoserver 3_使用GeoServer 和 mapbox-gl 搭建离线地图服务
  11. MaxtoCode问题说明汇总 (更新至 1.16 版)
  12. Cannot locate a 64-bit Oracle Client library:The specified module could not be found.
  13. SmartScore 64 Professional Edition v11.3.76 WiN 专业乐谱扫描识别软件
  14. 一个计算机网络题目——给局域网分配合适的网络前缀。
  15. [Effective C++ --014]在资源管理类中小心copying行为
  16. android 4.4 flac,如何在Android中将音频原始转换为FLAC
  17. Pandas中的appy和applymap
  18. 树莓派搭建onlyoffice-documentserver并使其可用
  19. 李航《统计学习方法》系列Python实现
  20. 移动硬盘格式化恢复软件下载

热门文章

  1. 把游戏里面的 UI 做成前端组件库会怎么样?
  2. 幂级数求和难吗?细节很重要
  3. python项目概述_Python简介
  4. 刀具更换策略问题(完工)
  5. 半导体材料 MOOC学习记录 第十章 III-V族化合物半导体
  6. 稻草人项目--项目的数据处理流程-- ( day03 )
  7. 停车场管理系统C语言作业,c语言课程设计报告停车场管理系统
  8. FPGA实现PI控制
  9. mysql 生成随机(数字、英文字符、汉字函数)
  10. Android 系统增加字体库及修改系统默认字体