文章目录

  • 一、题目解读
    • 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(nlog⁡n)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相关推荐

  1. HDU 1007 Quoit Design(分治)

    Description   给出n个点的坐标,输出点集中距离最近两点间距离的一半  Input   多组输入,每组用例第一行为点数n,之后n行每行两个浮点数表示一个点的横纵坐标,以n=0结束输入  O ...

  2. 杭电1007 Quoit Design

    题目内容: Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat ...

  3. (nlogn)的时间复杂度求 最近点对 hdu 1007 凹凸曼与小怪兽的故事 poj3714 Raid...

    hdu 1007  Quoit Design http://acm.hdu.edu.cn/showproblem.php?pid=1007 zoj 2107 Quoit Design http://a ...

  4. HDU1007 Quoit Design 分治+递归

    点击打开链接 Quoit Design Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Oth ...

  5. HDU1007(Quoit Design)

    Quoit Design 题目传送门 Problem Description Have you ever played quoit in a playground? Quoit is a game i ...

  6. 【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 ...

  7. hdu 1007(最近点对)

    最近点对问题定义:已知上m个点的集合,找出对接近的一对点.      在二维空间里,可用分治法求解最近点对问题.预处理:分别根据点的x轴和y轴坐标进行排序,得到X和Y,很显然此时X和Y中的点就是S中的 ...

  8. 杭电OJ分类题目(1)

    原题出处:HDOJ Problem Index by Type,http://acm.hdu.edu.cn/typeclass.php 杭电OJ分类题目(1) HDU Introduction HDU ...

  9. HDU题目分类大全【大集合】

    基础题: 1000.1001.1004.1005.1008.1012.1013.1014.1017.1019.1021.1028.1029.  1032.1037.1040.1048.1056.105 ...

最新文章

  1. 刷过一题之黑魔法师之门
  2. Oracle 12c RAC 日志体系结构的变化
  3. IT大数据服务管理高级课程(IT服务,大数据,云计算,智能城市)
  4. rsync 常见错误与解决方法整理
  5. centos 卸载自带的 java
  6. java date dateformat_Java中SimpleDateFormat的使用方法
  7. rtsp,rtp,gb28181直接转化为html5播放(二)
  8. 微信回应 iOS 13.2 杀后台;谷歌以 21 亿美元收购 Fitbit;优麒麟 19.10.1 发布 | 极客头条...
  9. Appium Server
  10. 安装激活visio2013 professional版本
  11. 关注物业公司信息化建设
  12. ie 无人操作自动关闭_Win10系统下ie浏览器无响应白屏自动关闭如何修复
  13. 从源码角度上探索AdapterViewFlipper怎么实现广告栏的垂直自动滚动
  14. 吉他C大调和弦高把位图
  15. 网络推广除了SEO优化还有这些方法你知道吗?
  16. 两位数合并成一个四位数的C++代码
  17. 李笑来python自学_自学是门手艺--李笑来
  18. 万维考试系统题库答案python_万维题库与试卷管理系统
  19. moodle平台二次开发
  20. 中国式众筹:促销,众筹?(转)

热门文章

  1. 帆软报表邮箱验证码登录
  2. Objectove-c单例模式
  3. juyter显示决策树图形_关于决策树可视化的treePlotter(学习笔记)
  4. python pandas模块_Python3.5 Pandas模块中Series用法详解
  5. AcWing321.棋盘分割(区间DP)题解
  6. 中文信息处理—已分词标注语料的抽取词表和文本还原
  7. AI人工智能 / ML机器学习专业词汇集
  8. Markdown Cookbook by Eric
  9. Python——如何将不规范的英文名字转化为“首字母大写,其他字母小写”的规范名字
  10. java中的URLConnection