HDU.1007 Quoit Design
文章目录
- 一、题目解读
- 1、原题
- 2、分类
- 3、题意
- 4、输入输出格式
- 5、数据范围
- 二、题解参考
- 1、总体思路
- 2、思路②
- (1).分析
- (2).AC代码
- 三、总结与后话
- 1、评价
- 2、后话
一、题目解读
1、原题
HDU.1007 Quoit Design
2、分类
分治法——最近点对
3、题意
给定一些点,求一个圆的半径、满足“圆最多只能使1个点在其内部”。
再稍微转化一下,就是求一堆点里最小的两点间距,然后再除以222。
4、输入输出格式
输入/输出 | 要求与格式 |
---|---|
输入样例个数 | 通过输入N=0N=0N=0标识输入结束 |
输入格式(每个样例) | 第一行输入一个数NNN,后NNN行每行都输入一组坐标xxx、yyy(空格隔开) |
输出格式(每个样例) | 每行输出一个结果 |
输出精度 | 结果精确到小数点后222位 |
5、数据范围
数据 | 范围 |
---|---|
NNN | 2≤N≤1052 \leq N \leq 10^52≤N≤105 |
(x,y)(x, y)(x,y) | x,y∈Rx, y \in \mathbb{R}x,y∈R |
二、题解参考
1、总体思路
思路 | 时间复杂度 | 具体解释 |
---|---|---|
穷举法 | O(n2)O(n^2)O(n2) | 穷举所有两个点间的距离,找最小 |
分治法 | O(nlogn)O(n\log n)O(nlogn) | 求左右两个半区间的最小值,然后考虑跨区间的合并 |
2、思路②
(1).分析
分治法的主要思想是将大的问题划分为若干个小的子问题。
在这里主要就表现为,求若干个点的最小距离困难,但是求2、3个点的最小距离容易。因此,对n个点,我们先根据点的横坐标xxx进行排序,不断地划分左、右区间,一直划分到只剩2、3个点。
那么很显然,得到的是两个子区间各自内部的距离最小值,我们对这两个值求一个最小值得到ddd.
跨区间的部分要怎么考虑合并呢?跨区间的部分的合并显然不能一个一个列举,还是会变成穷举的时间复杂度O(n2)O(n^2)O(n2).因此,需要考虑优化。
仔细想想的话,我们可以肯定横坐标范围在[xmid−d,xmid+d]\left[ x_{mid} - d, x_{mid} + d \right][xmid−d,xmid+d]之外的点都不用考虑。因为要跨越左右区间,所以横坐标xmidx_{mid}xmid一定会在被比较的两个点的横坐标之间。
以xleft_i<xmid−dx_{left\_i} < x_{mid} - dxleft_i<xmid−d为例:
∵xleft_i<xmid−d且xright_j>xmid∴xright_j−xleft_i>d再结合两点间坐标公式,易知:left_i和right_j这两个点间距必定大于d\begin{aligned} &\because x_{left\_i} < x_{mid} - d且x_{right\_j} > x_{mid} \\ &\therefore x_{right\_j} - x_{left\_i} > d \\ &再结合两点间坐标公式,易知:\\ &left\_i和right\_j这两个点间距必定大于d \end{aligned}∵xleft_i<xmid−d且xright_j>xmid∴xright_j−xleft_i>d再结合两点间坐标公式,易知:left_i和right_j这两个点间距必定大于d
但是这样筛选出来的点仍然有可能有很多个,直接逐个比较的话仍然会超时,因此我们还需要根据其纵坐标yyy再进行一次优化。
我们将选出来的cntcntcnt个点根据纵坐标再进行一次升序排序,然后从前往后逐个求距离:第111个点逐个和后面cnt−1cnt - 1cnt−1个点求距离更新ddd、第222个点逐个和后面cnt−2cnt - 2cnt−2个点求距离更新ddd、……但是在比较的时候,如果第jjj个点的纵坐标yjy_jyj已经比第iii个点的纵坐标yiy_iyi多出ddd,即yj−yi>dy_j - y_i > dyj−yi>d,那么从第jjj个点开始往后的点都不可能起到更新ddd的作用,所以直接break
出去,开始外层循环的下一次循环。
这样优化以后,效率会好很多。(印象中当时老师讲的时候说过,有人证明了XXXX,说明了XXXXX最多只会有6个点,所以效率会好很多)
(注):本文的代码参考了这篇文章的代码,因此代码相似度将近95%,本文的思路是对这个代码进行分析理解得到的。
(2).AC代码
HDU(C++/G++)AC代码如下:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>#define N 100005using namespace std;struct node
{double x;double y;
}us[N];int a[N];// 将坐标根据x升序排列
bool cmp_x(const node& a, const node&b)
{return a.x < b.x;
}// 将坐标索引根据对应的y升序排列进行排列
bool cmp_yi(int a, int b)
{return us[a].y < us[b].y;
}// 计算两点间距
inline double dis(node p1, node p2)
{return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}double find(int l, int r)
{// 分治到只剩两个点if (l + 1 == r)return dis(us[l], us[r]);// 分治到只剩三个点if (l + 2 == r)return min(min(dis(us[l], us[l + 1]), dis(us[l + 1], us[r])), dis(us[l], us[r]));// 寻找左、右半个区间内的最大、最小距离int mid = (l + r) >> 1;double d = min(find(l, mid), find(mid + 1, r));// 合并左右区间的最小距离// (在x ∈ [mid.x - d, mid.x + d]的范围内寻找,再根据纵坐标排序,效率可以提高很多)int cnt = 0;for (int i = l; i <= r; ++i)if (us[i].x >= us[mid].x - d && us[i].x <= us[mid].x + d)a[cnt++] = i;sort(a, a + cnt, cmp_yi);for (int i = 0; i < cnt; ++i)for (int j = i + 1; j < cnt; ++j){if (us[a[j]].y - us[a[i]].y >= d)break;d = min(d, dis(us[a[i]], us[a[j]]));}return d;
}int main()
{ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int n;while (cin >> n, n){// 输入for (int i = 0; i < n; ++i)cin >> us[i].x >> us[i].y;// 以x升序、将n个坐标进行排序sort(us, us + n, cmp_x);// 输出分治法查找的结果cout << fixed << setprecision(2) << find(0, n - 1) / 2 << endl;}return 0;
}
三、总结与后话
1、评价
这道题目是一道很典型的分治法例题——“求最近点对”。
2、后话
看了10min题目,才想起来这是去年暑假培训的时候老师讲过的;搜了又搜,才想起来这道题题型是“求最近点对”。
当时将分治法、分治思想的时候,感觉还是有所领悟的(除了二分答案我有点懵),半年内,刷的题合起来总共不到30题。到了半年后的今天,居然连分治法的结构长什么样子都记不太清楚了,实在是丢人。
也当做是个毒鸡汤,警示所有人,ACM没有持续和稳定的刷题练习是很难有所长进的。
HDU.1007 Quoit Design相关推荐
- HDU 1007 Quoit Design(分治)
Description 给出n个点的坐标,输出点集中距离最近两点间距离的一半 Input 多组输入,每组用例第一行为点数n,之后n行每行两个浮点数表示一个点的横纵坐标,以n=0结束输入 O ...
- 杭电1007 Quoit Design
题目内容: Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat ...
- (nlogn)的时间复杂度求 最近点对 hdu 1007 凹凸曼与小怪兽的故事 poj3714 Raid...
hdu 1007 Quoit Design http://acm.hdu.edu.cn/showproblem.php?pid=1007 zoj 2107 Quoit Design http://a ...
- HDU1007 Quoit Design 分治+递归
点击打开链接 Quoit Design Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Oth ...
- HDU1007(Quoit Design)
Quoit Design 题目传送门 Problem Description Have you ever played quoit in a playground? Quoit is a game i ...
- 【HDU - 1031 】Design T-Shirt(水题 排序)
题干: Soon after he decided to design a T-shirt for our Algorithm Board on Free-City BBS, XKA found th ...
- hdu 1007(最近点对)
最近点对问题定义:已知上m个点的集合,找出对接近的一对点. 在二维空间里,可用分治法求解最近点对问题.预处理:分别根据点的x轴和y轴坐标进行排序,得到X和Y,很显然此时X和Y中的点就是S中的 ...
- 杭电OJ分类题目(1)
原题出处:HDOJ Problem Index by Type,http://acm.hdu.edu.cn/typeclass.php 杭电OJ分类题目(1) HDU Introduction HDU ...
- HDU题目分类大全【大集合】
基础题: 1000.1001.1004.1005.1008.1012.1013.1014.1017.1019.1021.1028.1029. 1032.1037.1040.1048.1056.105 ...
最新文章
- 刷过一题之黑魔法师之门
- Oracle 12c RAC 日志体系结构的变化
- IT大数据服务管理高级课程(IT服务,大数据,云计算,智能城市)
- rsync 常见错误与解决方法整理
- centos 卸载自带的 java
- java date dateformat_Java中SimpleDateFormat的使用方法
- rtsp,rtp,gb28181直接转化为html5播放(二)
- 微信回应 iOS 13.2 杀后台;谷歌以 21 亿美元收购 Fitbit;优麒麟 19.10.1 发布 | 极客头条...
- Appium Server
- 安装激活visio2013 professional版本
- 关注物业公司信息化建设
- ie 无人操作自动关闭_Win10系统下ie浏览器无响应白屏自动关闭如何修复
- 从源码角度上探索AdapterViewFlipper怎么实现广告栏的垂直自动滚动
- 吉他C大调和弦高把位图
- 网络推广除了SEO优化还有这些方法你知道吗?
- 两位数合并成一个四位数的C++代码
- 李笑来python自学_自学是门手艺--李笑来
- 万维考试系统题库答案python_万维题库与试卷管理系统
- moodle平台二次开发
- 中国式众筹:促销,众筹?(转)
热门文章
- 帆软报表邮箱验证码登录
- Objectove-c单例模式
- juyter显示决策树图形_关于决策树可视化的treePlotter(学习笔记)
- python pandas模块_Python3.5 Pandas模块中Series用法详解
- AcWing321.棋盘分割(区间DP)题解
- 中文信息处理—已分词标注语料的抽取词表和文本还原
- AI人工智能 / ML机器学习专业词汇集
- Markdown Cookbook by Eric
- Python——如何将不规范的英文名字转化为“首字母大写,其他字母小写”的规范名字
- java中的URLConnection