两种方法对最近对问题的解释

背景描述:

  终于,隔了将近一周,开始更新第二篇算法博客。今天的问题是最近对问题。问题描述如下:对于二维坐标系中的若干个点,从中判断出相距最近的两个点,并输出最近的这个距离。
  我之前也翻看了很多篇博客,大家都解释的很好,但是都只是输出了最近的距离,而我希望这个程序不仅能输出最近距离,同时还能锁定是哪两个点得到的这个最近距离。于是,经过反复试错后,终于得到满意的结果,马不停蹄过来更新博客了。

蛮力法:

  首先介绍蛮力法的思路。顾名思义,就是从第一个点开始,求它和第二个点之间的距离,然后求它和第三个点之间的距离,依次往后遍历。经过两重循环之后就可以得出最短的距离,同时锁定是哪两个点产生的。
  可以设置两个一维数组,一个存储横坐标,另一个存储纵坐标,注意要两个数组彼此之间一一对应。完整算法如下(由于蛮力法较为简单,此处只给出算法部分,完整程序请参考下面分治法):

//返回最短长度,并得到该两个点在数组中的下标索引index1和index2
float Getclosedpoint(int *x, int *y, int n, int &index1, int &index2)
{float min = (x[0] - x[1])*(x[0] - x[1]) + (y[0] - y[1])*(y[0] - y[1]);float path;for (int i = 0; i < n - 1; i++){for (int j = i + 1; j < n; j++){path = (x[i] - x[j])*(x[i] - x[j]) + (y[i] - y[j])*(y[i] - y[j]);if (path <= min){min = path;index1 = i;index2 = j;}}}return min;
}

蛮力法时间复杂度分析:

  假设有n个点,则从外层循环是从第一个数字开始,循环到第n-1个数停止,共循环n-1次。内层循环一开始从第一个数开始,遍历求与后面所有的点之间的距离,共n-1次,最后一次循环从第n-1个数开始,求和第n个数之间的距离,执行1次。所以共执行1+2+…+(n-2)+(n-1)=n(n-1)/2;所以时间复杂度O(n2).

分治法

  分治法顾名思义是分而治之,将一个大问题分解成几个小问题再逐个解决。对于最近对问题,分治法的思路如下:
  1.首先将这些杂乱的点按照横坐标进行排序,然后取中间值mid将这堆点分成左右两部分。
  2.分别对左边和右边的两小堆点集再次递归使用分治法,进而得到对应的最短距离d1和d2。
  3.接下来处理mid中间线部分的情况。因为有一种可能就是距离最短的两个点一个在左区域一个在右区域。因此我们要对这种情况进行解决。办法是从刚才第二步中的两个结果中取最小值d,然后以步骤1中的中间值mid为基准,划分出宽度为2d的一个区域,然后将这个区域中的点进行蛮力法求得对应的最短距离d3。
  4.最后将结果进行比较。
  算法的完整程序如下:

#include<iostream>
#include<math.h>
#include<time.h>
using namespace std;struct point {int x, y;
};//对数组R[low]到R[hjgh]之间进行一次划分,返回划分之后中枢轴的位置
int Partition(point *R, int low, int high)
{int pivotkey;R[0] = R[low];pivotkey = R[low].x;while (low < high){while (low < high&&R[high].x >= pivotkey)high--;if (low < high)R[low++] = R[high];while (low < high&&R[low].x <= pivotkey)low++;if (low < high)R[high--] = R[low];}R[low] = R[0];return low;
}
//对记录序列R[s..t]进行快速排序
void Sort(point *R, int s, int t)
{int pivotloc;if (s < t){pivotloc = Partition(R, s, t);Sort(R, s, pivotloc - 1);Sort(R, pivotloc + 1, t);}
}
//对数组R[]进行快速排序 R[0]为哨兵单元
void QuickSort(point *R, int n)
{Sort(R, 1, n - 1);
}double Distance(point a, point b)
{return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}int index(double x, point *S, int low, int high)
{for (int i = 0; i < high - low + 1; i++){if (S[i].x <= x && S[i + 1].x > x)return i;}
}//对点坐标数组S[low]和S[high]之间的元素进行递归查找,返回其中最近的两个点之间的距离
//其中loc1,loc2表示这两个点在S[]中的下标
double Closest(point S[], int low, int high,int &loc1,int &loc2)
{double d1, d2, d3, d;int a1, b1, a2, b2;  //用于递归时记录最近对点的坐标int mid;int n1 = 0;   //递归函数中,用来表示最近对的下标int n2 = 0;if (high - low == 1)   //只有两个点{loc1 = low;loc2 = high;return Distance(S[low], S[high]);}if (high - low == 2)   //只有三个点,求最近距离{d1 = Distance(S[low], S[low + 1]);d2 = Distance(S[low + 1], S[high]);d3 = Distance(S[low], S[high]);if ((d1 < d2) && (d1 < d3)){loc1 = low;loc2 = low + 1;return d1;}else if (d2 < d3){loc1 = low + 1;loc2 = high;return d2;}else{loc1 = low;loc2 = high;return d3;}}mid = (low + high) / 2;     //计算中间点d1 = Closest(S, low, mid, a1, a2);   //递归求解子问题1d2 = Closest(S, mid + 1, high, b1, b2);   //递归解决子问题2if (d1 < d2)                      //以下求解子问题3{d = d1;loc1 = a1;loc2 = a2;}else{d = d2;loc1 = b1;loc2 = b2;}//筛选范围 S[mid].x-d, S[mid].x+dint index1 = 0;int index2 = 0;for (int i = 0; i < high - low + 1; i++){if (S[i].x <= S[mid].x - d && S[i + 1].x > S[mid].x - d){index1 = i;break;}}for (int i = 0; i < high - low + 1; i++){if (S[i].x <= S[mid].x + d && S[i + 1].x > S[mid].x + d){index2 = i;break;}}//对S[index1]和S[index2]之间进行蛮力法for (int i = index1; i < index2 - index1; i++){for (int j = i + 1; j < index2 - index1; j++){if (S[j].y - S[i].y >= 0)break;else{d3 = Distance(S[i], S[j]);if (d3 < d){d = d3;loc1 = i;loc2 = j;}}}}return d;
}int main()
{point *S = new point[11];int x[10] = { 12,14,4,77,89,9,99,96,77,93 };int y[10] = { 13,56,55,67,34,21,65,78,87,22 };S[0].x = 0;S[0].y = 0;for (int i = 1; i < 11; i++){S[i].x = x[i - 1];S[i].y = y[i - 1];}QuickSort(S, 11);int index1 = 0;int index2 = 0;cout << Closest(S, 1, 10, index1, index2) << endl;//cout << index1 << " " << index2 << endl;cout << "(" << S[index1].x << "," << S[index1].y << ") 和 (" << S[index2].x << "," << S[index2].y << ")" << endl;cout << "The run time is:" << (double)clock() / CLOCKS_PER_SEC << "s" << endl;
}

分治法的时间复杂度分析

  对于分治法,假设有k个数,当k=2时,时间复杂度为:T(n)=1;
当k>2时,时间复杂度为T(n)=2T(n/2)+n;对这样的递推式最终得到T(n)=O(nlog2n )。

算法总结

  对于分治法,有三点总结:1.写递归函数时,一定一定一定要考虑到递归跳出的情况,写出这种情况时如何return。2.对于确定点的坐标,递归函数中将index作为引用参数,传入函数体内,这种思路没毛病,需要注意的是,在函数体内再次调用递归函数时,传入的引用不能再是index,要用新的变量。否则的话index就得不到想要的值。3.对于递归函数,也是可以用new函数动态分配内存空间的,如果报错,原因极可能是代码出错。
  最后的最后,这几天莫名的有些焦虑。因为挑战杯,因为大学生计算机设计大赛,很多比赛摆在面前但是我却不知道怎么参加,不知道和谁一起参加,不知道自己的能力够不够参加,但是内心对于参赛这种经历的渴望又在催促我去参加。自我的怀疑和对未知的渴望在我心中纠缠,好焦虑。唉,明天还是去找老师聊一聊伐。

蛮力法-分治法-处理最近对问题相关推荐

  1. 求解最大连续子序列和问题(Java)蛮力法+分治法

    求解最大连续子序列和问题 [问题描述] 给定一个有n(n>=1)个整数的序列,要求求出其中最大连续子序列的和. [样例输入] 6 -2 11 -4 13 -5 -2 [样例输出] 20 [问题求 ...

  2. 最近点对问题(蛮力法和分治法)

    最近点对问题(蛮力法和分治法) 1.一维空间 1.1蛮力法 1.2分治法 2.二维空间 代码参考链接: http://t.csdn.cn/flREB 1.一维空间 1.1蛮力法 代码: import ...

  3. 蛮力法分硬币问题 c++ cpp

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 问题 一.问题分析 二.问题解决 1.就那么点代码 2.测试结果 总结 问题 提示:这里可以添加本文要记录的大概内容: 用以 ...

  4. 演算法 - 分治法(Divide-and-Conquer)

    排版真的乱到一个 ¥*@#&? 一,Divide-and-Conquer(分治法) 二,Recurrences(递归) 1,替代法(Substitution method) 2,Tree Me ...

  5. 求最大字段和问题(常规法,分治法,动态规划法)

    算法设计与分析-----求最大字段和问题 问题描述:给定由n个整数组成的序列(a1,a2,a3......,an),求该序列的子段的最大值. 常规法: 从a1开始,求出以a1开头的子序列最大的和为su ...

  6. 005-算法-分治法

    一.概念: 在计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以 ...

  7. 螺旋方阵(列举法,分治法,java版,逆时针)

    目录 螺旋方阵介绍 1.适合基础薄弱同学的 列举法 2.螺旋方阵代码 螺旋方阵介绍 所谓"螺旋方阵",是指对任意给定的N,将1到N×N的数字从左上角第1个格子开始,按顺时针螺旋方向 ...

  8. 深大算法设计与分析实验二——分治法求最近点对问题

    源代码: 深大算法设计与分析实验二--分治法求最近点对问题代码-C/C++文档类资源-CSDN下载 目录 实验问题 一.实验目的: 二.内容: 三.算法思想提示 产生不重复的随机点算法: 蛮力算法: ...

  9. 算法设计与分析 实验二 分治法求解最近点对问题

    分治法求解最近点对问题 一.实验目的与要求 1.实验基本要求 2.实验亮点 二.实验内容与方法 三.实验步骤与过程 (一)一些准备工作 1.实验流程 2.数据生成与去除重复点 (二)暴力穷举法 1.算 ...

最新文章

  1. 超级账本(Hyperledger Fabric)之权限管理浅析
  2. eeglab中文教程系列(18)-自己创建电极位置以及电极位置文件
  3. java long to float_为什么Java中long可以自动转换成float
  4. Coding Party 邀你出战!飞桨黑客马拉松线下场来啦
  5. 一般编译器错误_[翻译]MLIR:摩尔定律终结的编译器基础结构
  6. Create-React-App创建antd-mobile开发环境
  7. 《linux核心应用命令速查》连载一:accton:打开或关闭进程统计
  8. [.NET] 使用 .NET Framework 開發 ActiveX Control
  9. 最优秀的一到五个国产软件
  10. 基于Matlab的随机森林算法实现(附算法介绍及代码详解)
  11. 细胞穿膜肽TAT/血管肽Angiopep/靶向多肽cRGD偶联TIO2二氧化钛纳米粒(TiO2-Angiopep)
  12. 阳光下,我们是幸福的孩子
  13. windows常用系统命令
  14. 万能表单php设计思路,在线自定义万能表单的设计思路
  15. Application Server was not connected Unable to ping server at localhost:1099
  16. 【华为OD统一考试B卷 | 100分】按身高和体重排队(C++ Java JavaScript Python)
  17. 基于Web实现网络拓扑图
  18. Java基础知识笔记-11_2-Swing用户界面组件
  19. 手披云雾开鸿蒙,元朝关于泰山的古诗词
  20. [jni] [android] 用C++开发安卓程序

热门文章

  1. 纯手工采用java编写双色球、大乐透随机生成算法,真实模拟出球
  2. 使用 KubeSphere 和极狐GitLab 打造云原生持续交付系统
  3. dxf素材和dxf、plt、dst看图软件
  4. unity(登录注册用手机号短信验证)
  5. 计算机属性显示缩略图 桌面样式变了,Win7任务栏缩略图预览变成列表预览怎么解决?...
  6. python-关于时间处理的知识
  7. DOTS支持的shader
  8. win7 上配置openGL开发环境(配套openGL 超级宝典Super Bible 6th)
  9. 2022强大的修复版趣味心理测试小程序源码,趣味测试引流裂变神器,流量主激励广告实现管道收益
  10. tensorflow进阶(更新中...)