分治应用--最近点对问题 POJ 3714

文章目录

    • 1. 问题描述
    • 2. 解题思路
    • 3. 实现代码
    • 4. POJ 3714

1. 问题描述

二维平面上有n个点,如何快速计算出两个距离最近的点对?

2. 解题思路

  • 暴力做法是,每个点与其他点去计算距离,取最小的出来,复杂度O(n2)
  • 采用分治算法
  1. 将数据点按照 x 坐标排序,找到中位点,过中位点划线 x = mid_x 将数据分成2部分,递归划分,直到两个半边只有1个或者2个数据,只有1个数据点,最短距离返回无穷大,有2个点直接返回2点的距离
  2. 合并左右两边的结果,取左右两边的最短距离的较小值为 d = min{dl,dr},那么在 x = mid_x 的 ± d 范围内的左右点对才有可能距离比 d 更小(好理解)
  3. 对这个范围内的点,再按照 y 坐标排序,查找两个点的 y 差值小于 d 的点对(重点在这里,见下面分析),计算其距离是否比 d 更小
    在这里插入图片描述
    假如在这个范围内的有1,2,3,4,5,6六个点(按 y 坐标排序),寻找距离小于 d 的点对,如果暴力查找,复杂度还是 n2,我们可以看出点4只有可能在其上下y坐标 ± d 的范围内找到满足距离小于 d 的点匹配,点1和点4不可能距离小于 d,左边的点最多可以有4个右边的点使得其距离小于 d
    在这里插入图片描述
    所以,步骤3是O(n)复杂度。
    T(1) = 1;T(n) = 2*T(n/2)+n;高中数学即可求得T(n)是O(nlogn)的复杂度。

3. 实现代码

/*** @description: 2维平面寻找距离最近的点对(分治)* @author: michael ming* @date: 2019/7/4 23:16* @modified by: */
#include <iostream>
#include <cmath>
#include <vector>
#include <ctime>
#include <algorithm>
#define LEFT_BOUND 0.0
#define RIGHT_BOUND 100.0
#define LOWER_BOUND 0.0
#define UPPER_BOUND 100.0   //随机点的范围
using namespace std;
class Point//点
{
public:int id;double x, y;Point(int index, double x0, double y0):id(index),x(x0),y(y0){}
};
typedef vector<Point> PointVec;
bool compx(const Point &a, const Point &b)
{if(a.x != b.x)return a.x < b.x;return a.y < b.y;
}
bool compy(const Point &a, const Point &b)
{return a.y < b.y;
}class ClosestPoint
{PointVec points_vec;int numOfPoint;
public:ClosestPoint(){srand(unsigned(time(0)));double x, y;cout << "请输入测试点个数,将随机生成散点:";cin >> numOfPoint;for(int i = 0; i < numOfPoint; ++i){x = LEFT_BOUND + (double)rand()/RAND_MAX *(RIGHT_BOUND-LEFT_BOUND);y = LOWER_BOUND + (double)rand()/RAND_MAX *(UPPER_BOUND-LOWER_BOUND);cout << i+1 << " (" << x << "," << y << ")" << endl;points_vec.emplace_back(i+1,x,y);//生成点的动态数组}}double dist(const Point &a, const Point &b){double dx = a.x - b.x;double dy = a.y - b.y;return sqrt(dx*dx + dy*dy);//返回两点之间的距离}void bfCalDist()//暴力求解{size_t num = points_vec.size();if(num <= 1){cout << "输入个数<=1 !!!" << endl;return;}int i, j, s, t;double distance = RAND_MAX, d;for(i = 0; i < num; ++i)for(j = i+1; j < num; ++j){d = dist(points_vec[i], points_vec[j]);if(d < distance){distance = d;s = points_vec[i].id;t = points_vec[j].id;}}cout << "点" << s << "到点" << t << "的距离最小:" << distance << endl;}double calcDist(size_t left, size_t right, size_t &s, size_t &t){if(left == right)//一个点,返回无穷大return RAND_MAX;if(left+1 == right)//两个点,直接计算距离{s = points_vec[left].id;t = points_vec[right].id;return dist(points_vec[left],points_vec[right]);}sort(points_vec.begin()+left,points_vec.begin()+right+1,compx);//把点群按照x排序size_t mid = (left+right)/2;double mid_x = points_vec[mid].x;double distance = RAND_MAX, d;distance = min(distance,calcDist(left,mid,s,t));//递归划分左边distance = min(distance,calcDist(mid+1,right,s,t));//递归划分右边size_t i, j, k = 0;PointVec temp;//存储临时点(在mid_x左右d范围内的)for(i = left; i <= right; ++i){if(fabs(points_vec[i].x-mid_x) <= distance){temp.emplace_back(points_vec[i].id,points_vec[i].x,points_vec[i].y);k++;}}sort(temp.begin(),temp.end(),compy);//再把范围内的点,按y排序for(i = 0; i < k; ++i){for(j = i+1; j < k && temp[j].y-temp[i].y < distance; ++j){//在临时点里寻找距离更小的,内层循环最多执行不超过4次就会退出d = dist(temp[i],temp[j]);if(d < distance){distance = d;s = temp[i].id;t = temp[j].id;}}}return distance;}void closestDist()//调用分治求解{size_t num = points_vec.size();if(num <= 1){cout << "输入个数<=1 !!!" << endl;return;}size_t s, t; s = t = 0;//记录起终点double d = calcDist(0,num-1,s,t);cout << "点" << s << "到点" << t << "的距离最小:" << d << endl;}};
int main()
{ClosestPoint cp;clock_t start, end;cout << "方法1,暴力求解:" << endl;start = clock();cp.bfCalDist();end = clock();cout << "耗时:" << (double)(end - start) << "ms." << endl;cout << "-------------------" << endl;cout << "方法2,分治求解:" << endl;start = clock();cp.closestDist();end = clock();cout << "耗时:" << (double)(end - start) << "ms." << endl;return 0;
}

在这里插入图片描述

4. POJ 3714

http://poj.org/problem?id=3714
相同的问题,只是数据位置分为2类(人,核电站),计算距离时,需判断是不同的类,否则返回一个很大的数。

以下代码显示Wrong Answer,谁帮忙看下。测试样例输出是一样的。
在这里插入图片描述

/*** @description: poj3714求解最近的核电站距离* @author: michael ming* @date: 2019/7/6 0:09* @modified by: */
#include<iomanip>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#define DBL_MAX 1.7976931348623158e+308
using namespace std;
class Point//点
{
public:int id;int x, y;Point(int index, int x0, int y0):id(index),x(x0),y(y0){}
};
typedef vector<Point> PointVec;
bool compx(const Point &a, const Point &b)
{if(a.x != b.x)return a.x < b.x;return a.y < b.y;
}
bool compy(const Point &a, const Point &b)
{return a.y < b.y;
}class ClosestPoint
{PointVec points_vec;int numOfPoint;
public:ClosestPoint(){int x, y;cin >> numOfPoint;for(int i = 0; i < numOfPoint; ++i){cin >> x >> y;points_vec.push_back(Point(0,x,y));//生成站点的动态数组(0表示站)}for(int i = 0; i < numOfPoint; ++i){cin >> x >> y;points_vec.push_back(Point(1,x,y));//加入人的位置(1表示人)}}double dist(const Point &a, const Point &b){if(a.id == b.id)return DBL_MAX;//相同的类型,返回很大的数int dx = a.x - b.x;int dy = a.y - b.y;return sqrt(double(dx*dx + dy*dy));//返回两点之间的距离}double calcDist(size_t left, size_t right){if(left == right)//一个点,返回无穷大return DBL_MAX;if(left+1 == right)//两个点,直接计算距离{return dist(points_vec[left],points_vec[right]);}sort(points_vec.begin()+left,points_vec.begin()+right+1,compx);//把点群按照x排序size_t mid = (left+right)/2;double mid_x = points_vec[mid].x;double distance = DBL_MAX, d;distance = min(distance,calcDist(left,mid));//递归划分左边distance = min(distance,calcDist(mid+1,right));//递归划分右边size_t i, j, k = 0;PointVec temp;//存储临时点(在mid_x左右d范围内的)for(i = left; i <= right; ++i){if(fabs(points_vec[i].x-mid_x) <= distance){temp.push_back(Point(points_vec[i].id,points_vec[i].x,points_vec[i].y));k++;}}sort(temp.begin(),temp.end(),compy);//再把范围内的点,按y排序for(i = 0; i < k; ++i){for(j = i+1; j < k && temp[j].y-temp[i].y <= distance; ++j){//在临时点里寻找距离更小的,内层循环最多执行不超过4次就会退出d = dist(temp[i],temp[j]);if(d < distance){distance = d;}}}return distance;}double closestDist()//调用分治求解{size_t num = points_vec.size();return calcDist(0,num-1);}};
int main()
{int times;cin >> times;while (times--){ClosestPoint cp;cout << fixed << setprecision(3) << cp.closestDist() << endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/480137.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java多线程系列(十):源码剖析AQS的实现原理

在并发编程领域&#xff0c;AQS号称是并发同步组件的基石&#xff0c;很多并发同步组件都是基于AQS实现&#xff0c;所以想掌握好高并发编程&#xff0c;你需要掌握好AQS。 本篇主要通过对AQS的实现原理、数据模型、资源共享方式、获取锁的过程&#xff0c;让你对AQS的整体设计…

玩转二算法课的笔记-第一章

1 问题&#xff1a;对一组数据进行排序 回答&#xff1a;快速排序算法o(NLOGN)&#xff0c;错误。 关键词&#xff1a;思考 应该问面试官&#xff0c;这组数据有什么样的特征&#xff1f; 比如;有没有可能包含大量重复的元素&#xff1f; 如果有这个可能的话&#xff0c;三路快…

微软亚洲研究院NLC组招聘实习生!与一线研究员共探NLP前沿与落地!

星标/置顶小屋&#xff0c;带你解锁最萌最前沿的NLP、搜索与推荐技术MSRA-NLC组招人啦&#xff01;微软亚洲研究院&#xff08;MSRA&#xff09;自然语言计算组&#xff08;NLC&#xff09;招收长期实习生一名&#xff0c;与一线研究员共同进行自然语言处理领域的科研项目和落地…

分治应用--万里挑一 找假硬币

文章目录1. 问题描述2. 解题思路3. 代码实现1. 问题描述 n 个硬币中有1枚是假币&#xff0c;真假币唯一的区别是假币重量轻&#xff0c;如何快速找出假币 2. 解题思路 暴力做法&#xff0c;一个一个的称重&#xff0c;O&#xff08;n&#xff09;复杂度分治思路 将硬币等分…

Java多线程与并发系列从0到1全部合集,强烈建议收藏!

在过去的时间中&#xff0c;我写过Java多线程与并发的整个系列。 为了方便大家的阅读&#xff0c;也为了让知识更系统化&#xff0c;这里我单独把Java多线程与并发的整个系列一并罗列于此&#xff0c;希望对有用的人有用&#xff0c;也希望能帮助到更多的人。 以下为整个目录&a…

论文浅尝 | 基于图注意力的常识对话生成

OpenKG 祝各位读者新春快乐&#xff0c;猪年吉祥&#xff01;来源&#xff1a;IJCAI 2018.论文下载地址&#xff1a;https://www.ijcai.org/proceedings/2018/0643.pdf项目源码地址&#xff1a;https://github.com/tuxchow/ccm动机在以前的工作中&#xff0c;对话生成的信息源是…

Facebook、阿里等大佬现身说法,NLP是否被高估了?

NLP (自然语言处理)&#xff0c;利用计算机对人类的语言文字进行处理。由于语言文字是人类交流沟通的最基本方式&#xff0c;因此 NLP 也是最典型的 AI 领域之一。NLP 被誉为“人工智能皇冠上的明珠”。这话也许没错&#xff0c;但听起来难免空洞。所以我去实际问了3位从事 NLP…

玩转算法面试-第二章

1 时间复杂度分析 正常处理的数据规模&#xff0c;为了保险起见&#xff0c;可将将上面的数在除以10&#xff0c;防止电脑假死。 空间复杂度分析&#xff1a; 注意问题&#xff1a;递归调用是有空间代价的 3 常见的复杂度分析 翻转的代码&#xff1a; 选择排序的方法&a…

论文笔记(Attentive Recurrent Social Recommendation)

注意力循环社交推荐 原文链接&#xff1a;Attentive Recurrent Social Recommendation, SIGIR’18 原理&#xff1a;将用户的朋友和历史交互项按时间划分&#xff0c;用注意力机制整合各个时段的朋友影响和交互项影响后输入LSTM来学习动态用户向量&#xff0c;动态用户向量与动…

回溯算法(Backtracking Algorithm)之八皇后问题

文章目录1. 回溯算法思想2. 算法应用2.1 八皇后问题1. 回溯算法思想 前面讲过贪心算法并不能保证得到最优解&#xff0c;那怎么得到最优解呢&#xff1f; 回溯思想&#xff0c;有点类似枚举搜索。枚举所有的解&#xff0c;找到满足期望的解。为了有规律地枚举所有可能的解&am…

最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

在Java并发场景中&#xff0c;会涉及到各种各样的锁&#xff0c;比如&#xff1a;高并发编程系列&#xff1a;4种常用Java线程锁的特点&#xff0c;性能比较、使用场景&#xff0c;这些锁有对应的种类&#xff1a;公平锁&#xff0c;乐观锁&#xff0c;悲观锁等等&#xff0c;这…

论文浅尝 | Generative QA: Learning to Answer the Whole Question

链接: https://openreview.net/forum?idBkx0RjA9tX传统的机器阅读理解的模型都是给定 context 和 question, 找出最有可能回答该 question 的 answer&#xff0c;用概率表示为 p(a|q,c)&#xff0c;这其实是一个判别模型。判别模型在大多数任务上可以取得比生成模型更好的准确…

打破BERT天花板:11种花式炼丹术刷爆NLP分类SOTA!

星标/置顶小屋&#xff0c;带你解锁最萌最前沿的NLP、搜索与推荐技术文 | JayLou娄杰编 | 小轶在2020这个时间节点&#xff0c;对于NLP分类任务&#xff0c;我们的关注重点早已不再是如何构造模型、拘泥于分类模型长什么样子了。如同CV领域当前的重点一样&#xff0c;我们更应该…

论文笔记(A Neural Influence Diffusion Model for Social Recommendation)

神经影响传播模型为了社交推荐 原文链接&#xff1a;A Neural Influence Diffusion Model for Social Recommendation, SIGIR’19 原理&#xff1a;社交网络上应用GNN提取朋友对用户的影响候选项对用户历史交互项的注意力影响用户向量&#xff0c;用户向量和项向量的内积预测评…

玩转算法面试-第三章

数组中常见的问题 排序&#xff1a; 选择排序&#xff1b;插入排序&#xff1b;归并排序&#xff1b;快速排序 查找&#xff1a;二分查找法 数据结构&#xff1a;栈&#xff1b;队列&#xff1b;堆 … 二分查找法&#xff1a; 1964年提出&#xff0c;没有bug的二分查找法是在1…

回溯应用-- 0-1背包问题

文章目录1. 问题描述2. 回溯解决思路1. 问题描述 0-1背包非常经典&#xff0c;很多场景都可以抽象成这个问题。经典解法是动态规划&#xff0c;回溯简单但没有那么高效。 有一个背包&#xff0c;背包总的承载重量是 W kg。现有n个物品&#xff0c;每个物品重量不等&#xff0…

Java多线程系列(五):线程池的实现原理、优点与风险、以及四种线程池实现

为什么需要线程池 我们有两种常见的创建线程的方法&#xff0c;一种是继承Thread类&#xff0c;一种是实现Runnable的接口&#xff0c;Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁&#xff0c;如果线程数量多的话&#xff0c;频繁…

论文浅尝 | 面向单关系事实问题的中文问答模型

来源&#xff1a;NLPCC 2017论文下载地址&#xff1a;http://tcci.ccf.org.cn/conference/2017/papers/2003.pdf动机开放领域的QA问题是一个被广泛研究的问题&#xff0c;而且目前这个问题并没有被很好地解决。在中文领域&#xff0c;相关的数据集并不多。而NLPCC开放了一个KBQ…

玩转算法值面试-第五章 -在链表中穿针引线

5-123 数组中可以随机访问&#xff0c;相反链表就不行 leetcode&#xff1a;206 反转一个链表&#xff0c;链表如果没有特别声明&#xff0c;则节点的值不发生改变 一共需要三个指针&#xff1a;current指向当前需要处理的指针 next指向当前需要处理的元素的下一个元素的指针…

论文笔记(SocialGCN: An Efficient Graph Convolutional Network based Model for Social Recommendation)

一个有效的基于图卷积神经网络的社交推荐模型 原文链接&#xff1a;SocialGCN: An Efficient Graph Convolutional Network based Model for Social Recommendation, arxiv 原理&#xff1a;在用户-项交互图上应用GNN来学习用户向量的表示&#xff0c;用户向量和项向量内积预测…