最近点对分治法
二维空间最近点对问题的分治算法伪代码
间的最近距离。
常用的解决方式是分治算法。
以下是分治算法的伪代码表示:假设我们的输入是一组点集,我们将它划分为几个部分,然后在每一部分内应用我们的搜索策略,最后将结果合并以得到整个点的最接近对。
```pythonfunction KPPSearch(points, k)if points is empty or k is 1return (points[0], points[0])else if k is 2return min(minDistance(points[left], points[right]), minDistance(points[right], points[middle]))mid = partition(points)closest = minDistance(points[mid], points[left])if k is 3 or closest is greater than 0return (mid, left)elseleftLeft = minDistance(points[left], points[leftLeft])leftRight = minDistance(points[left], points[leftRight])if leftLeft is greater than 0 and leftRight is greater than 0return (leftLeft, leftRight)elsereturn (left, leftRight)function partition(points)pivot = points[0]left = []middle = []right = []for point in points:if point is less than pivot in Euclidean distance:append(point to left)else:append(point to middle)for point in middle:append(point to right)return pivot, left, middle, right```上述伪代码中的主要步骤包括:分治法的核心步骤`partition`函数用于将数据集分为三部分,并且根据选择的"轴"进行划分;然后在每一个部分内,我们会使用这个方法进行搜索。
分而治之算法---距离最近的点对
距离最近的点对给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。
例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。
若知道任意两个洞的最小距离,可估计金属断裂的概率。
这种最小距离问题实际上也就是距离最近的点对问题。
通过检查所有的n(n- 1 ) / 2对点,并计算每一对点的距离,可以找出距离最近的一对点。
这种方法所需要的时间为(n2 )。
我们称这种方法为直接方法。
图1 4 - 1 3中给出了分而治之求解算法的伪代码。
该算法对于小的问题采用直接方法求解,而对于大的问题则首先把它划分为两个较小的问题,其中一个问题(称为A)的大小为「n /2ù,另一个问题(称为B)的大小为「n /2ù。
初始时,最近的点对可能属于如下三种情形之一: 1) 两点都在A中(即最近的点对落在A中);2) 两点都在B中;3) 一点在A,一点在B。
假定根据这三种情况来确定最近点对,则最近点对是所有三种情况中距离最小的一对点。
在第一种情况下可对A进行递归求解,而在第二种情况下可对B进行递归求解。
if (n较小) {用直接法寻找最近点对R e t u r n ; }// n较大将点集分成大致相等的两个部分A和B确定A和B中的最近点对确定一点在A中、另一点在B中的最近点对从上面得到的三对点中,找出距离最小的一对点图14-13 寻找最近的点对为了确定第三种情况下的最近点对,需要采用一种不同的方法。
这种方法取决于点集是如何被划分成A、B的。
一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。
位于垂线上的点可在A和B之间分配,以便满足A、B的大小。
例2-8 考察图14-14a 中从a到n的1 4个点。
这些点标绘在图14-14b 中。
中点xi = 1,垂线x = 1如图14-14b 中的虚线所示。
虚线左边的点(如b, c, h, n, i)属于A,右边的点(如a, e, f, j, k, l) 属于B。
1007分治法(最近点对)
由此可得:
C11 C12 C 21 C 22
A11 B11 A12 B21 A11 B12 A12 B22 A21 B11 A22 B21 A21 B12 A22 B22
Strassen矩阵乘法
(1 ) C12 A11 AO B11 B12 n 2 C11 T ( 12 n) 2 C 7 T ( n / 2 ) O ( n ) n2 C A A B B 22 22 21 22 21 21 M 1 A11 ( B12 B22 ) T(n)=O(nlog7) =O(n2.81)较大的改进 C11 M 5 M 4 M 2 M 6 M 2 ( A11 A12 ) B22
规模较小的情况
n=2
规模较小的情况
n=4
规模较小的情况
n=4
规模较小的情况
n=8
规模较小的情况
n=8
规模较大的情况
当k>0时,将2k×2k棋盘分割为4个2k-1×2k-1 子棋盘(a)所示。 特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特 殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘, 可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如 (b)所 示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归 地使用这种分割,直至棋盘简化为棋盘1×1。
Strassen矩阵乘法
传统方法:O(n3)
A和B的乘积矩阵C中的元素C[i,j]定义为:C[i][ j ] A[i][ k ]B[k ][ j ]
k 1 n
若依此定义来计算A和B的乘积矩阵C,则每计 算C的一个元素C[i][j],需要做n次乘法和n-1次 加法。因此,算出矩阵C的 个元素所需的计算 时间为O(n3)
最近点对问题
最近点对问题I.一维问题:一、问题描述和分析最近点对问题的提法是:给定平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。
严格的讲,最接近点对可能多于1对,为简单起见,只找其中的1对作为问题的解。
简单的说,只要将每一点与其它n-1个点的距离算出,找出达到最小距离的2点即可。
但这样效率太低,故想到分治法来解决这个问题。
也就是说,将所给的平面上n个点的集合S 分成2个子集S1和S2,每个子集中约有n/2个点。
然后在每个子集中递归的求其最接近的点对。
这里,关键问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决,但如果这2个点分别在S1和S2中,问题就不那么简单了。
下面的基本算法中,将对其作具体分析。
二、基本算法假设用x轴上某个点m将S划分为2个集合S1和S2,使得S1={x∈S|x<=m};S2={x ∈S|x>m}。
因此,对于所有p∈S1和q∈S2有p<q。
递归的在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设d=min{|p1-p2|,|q1-q2|}。
由此易知,S中的最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。
如下图所示:S1 S2p1 p2 p3 q1 q2 q3图1 一维情形的分治法注意到,如果S的最接近点对是{p3,q3},即|p3-q3|<d,则p3和q3两者与m的距离不超过d,即|p3-m|<d,|q3-m|<d。
也就是说,p3∈(m-d,m],q3∈(m,m+d]。
由于每个长度为d的半闭区间至多包含S1中的一个点,并且m是S1和S2的分割点,因此(m-d,m]中至少包含一个S中的点。
同理,(m,m+d]中也至少包含一个S中的点。
数据结构与算法之最近点对
思路:结合分治法 首先将输入的坐标组按x轴值用快接读出的x轴中值m 将坐标数组分为两部分 分别处理两个子段 两子部分返回最小的两点长度leng1,leng2 得到暂时最小的两点长度leng,为MIN(leng1,leng2) 这是两个两点p、q在同一个子集情况
然后就是求两个点p、q不在同一个子集的情况 使用两个游标i、j从m和m+1遍历两个子段 由于两个子集也为有序的 若两点横轴距离大于leng或者讨论满足横轴距离 和纵轴距离都小于leng的达到6个,可以跳出内 层遍历循环
leng1=maxLength(a,low,m); leng2=maxLength(a,m+1,high); leng=leng1<leng2?leng1:leng2; for (i=m;i>low-1;i--) for (num=6,j=m+1;j<high+1;j++) { if (a[j][1]-a[i][1]>leng) continue; if (a[j][0]-a[i][0]>leng || num==0) break; x=a[j][0]-a[i][0]; y=a[j][1]-a[i][1]; z=sqrt(x*x+y*y); num--; if (z<leng) leng=z; }
分治法二(平面最近点对)
分治法⼆(平⾯最近点对)上篇⽂章介绍了分治法的概念和基本解题步骤,并附加了⼀个例题帮助⼤家了解分治法的基本思想,在这篇⽂章中,我将对分治法的另⼀个经典问题进⾏分析,希望我的⽂章能够将今天的主题解释清楚。
接下来我将⽤三种不同的⽅法求解“平⾯最近点对”问题。
问题描述:在⼀个平⾯上随机分布着 n 个点,现给定 n 个点的坐标,要求给出最近的两个点之间的距离。
⽅法⼀:原始⽅法题⽬要求求出最近的两点之间的距离,先整理⼀下已知的线索:⾸先点的总个数为 n ;其次已知 n 个点的坐标。
掌握了每个点的坐标,就相当于间接地掌握了任意两点之间的距离。
假设两个点为 A : ( x1 , y1 ) , B : ( x2 , y2 ) ,两点间的距离为 distance ,根据平⾯坐标系中的两点间距离公式可得:distance ^ 2 = ( x1 - x2 ) ^ 2 + ( y1 - y2 ) ^ 2,运⽤该公式对每两个点的距离进⾏计算,并不断更新最⼩值 min_distance 。
核⼼代码为:这个⽅法很直观也最容易想到,不过,由以上的两层循环可知,该⽅法的时间复杂度为 o ( n ^ 2 ) ,当 n 的值不断增⼤时,这个⽅法处理起来就显得⼒不从⼼了。
因此我们必须寻找另⼀种更有效的⽅法,或者在此⽅法上进⾏适当的改进。
接下来⼀起了解⼀下第⼆种⽅法--分治法⽅法⼆:分治法为了做到有理有据,正式叙述解法之前,我得再啰嗦⼏句选择分治法的原因,希望不会引起⼤家的反感。
在本问题中,需要求得最近两点之间的距离,整个问题的规模为 n 个点,不妨将这 n 个点⼀分为⼆,就变成两个求解 n /2 个点规模下最近点对的距离问题,如此不断缩⼩规模,当变成两个点的规模下求解最近点对问题时,显⽽易见,即为这两个点的距离,这样随着问题规模的缩⼩解决的难易程度逐渐降低的特征正是可以⽤分治法解答的问题所具备的特征。
接下来,我们按照分治法解题步骤分割--求解--合并分析这个问题。
用分治法解决最近点对问题:python实现
⽤分治法解决最近点对问题:python实现 最近点对问题:给定平⾯上n个点,找其中的⼀对点,使得在n个点的所有点对中,该点对的距离最⼩。
需要说明的是理论上最近点对并不⽌⼀对,但是⽆论是寻找全部还是仅寻找其中之⼀,其原理没有区别,仅需略作改造即可。
本⽂提供的算法仅寻找其中⼀对。
解决最近点对问题最简单的⽅法就是穷举法,这样时间复杂度是平⽅级,可以说是最坏的策略。
如果使⽤分治法,其时间复杂度就是线性对数级,这样⼤⼤提⾼了效率。
⾸先⽤分治法解决该问题的基本思路可以参考 /lishuhuakai/article/details/9133961 ,说的很详细,但⼤致思路就是先根据x轴把所有点平分,然后分别在每⼀部分寻找最近点对,最后通过⽐较选⼀个最⼩的。
当然其中最核⼼的地⽅是跨域求距离,原⽂写的很清楚,在此就不再赘述了。
以下是代码:from math import sqrtdef nearest_dot(s):len = s.__len__()left = s[0:len/2]right = s[len/2:]mid_x = (left[-1][0]+right[0][0])/2.0if left.__len__() > 2: lmin = nearest_dot(left) #左侧部分最近点对else: lmin = leftif right.__len__() > 2: rmin = nearest_dot(right) #右侧部分最近点对else: rmin = rightif lmin.__len__() >1: dis_l = get_distance(lmin)else: dis_l = float("inf")if rmin.__len__() >1: dis_2 = get_distance(rmin)else: dis_2 = float("inf")d = min(dis_l, dis_2) #最近点对距离mid_min=[]for i in left:if mid_x-i[0]<=d : #如果左侧部分与中间线的距离<=dfor j in right:if abs(i[0]-j[0])<=d and abs(i[1]-j[1])<=d: #如果右侧部分点在i点的(d,2d)之间if get_distance((i,j))<=d: mid_min.append([i,j]) #ij两点的间距若⼩于d则加⼊队列if mid_min:dic=[]for i in mid_min:dic.append({get_distance(i):i})dic.sort(key=lambda x: x.keys())return (dic[0].values())[0]elif dis_l>dis_2:return rminelse:return lmin# 求点对的距离def get_distance(min):return sqrt((min[0][0]-min[1][0])**2 + (min[0][1]-min[1][1])**2)def divide_conquer(s):s.sort(cmp = lambda x,y : cmp(x[0], y[0])) nearest_dots = nearest_dot(s)print nearest_dots测试⼀下,⽐如说要找这些点中最近的⼀对s=[(0,1),(3,2),(4,3),(5,1),(1,2),(2,1),(6,2),(7,2),(8,3),(4,5),(9,0),(6,4)]运⾏⼀下divide_conquer(s),最终打印出[(6, 2), (7, 2)],Bingo。
最近点对算法
最近点对算法1. 简介最近点对算法(Closest Pair Algorithm)是一种用于找到平面上最近的两个点的算法。
该算法可以在给定一组点的情况下,找到距离最近的两个点,并计算出它们之间的距离。
最近点对问题在计算几何学、图像处理、数据挖掘等领域中具有广泛应用。
例如,在地理信息系统中,可以使用最近点对算法来查找距离最近的两个地理位置;在机器视觉中,可以使用该算法来寻找图像中距离最接近的两个特征点。
2. 算法思想最近点对算法采用分治策略,将问题划分为多个子问题,并通过递归求解子问题来得到整体解。
其基本思想可以概括为以下步骤:1.将所有点按照横坐标进行排序。
2.将排序后的点集平均划分为左右两部分,分别称为P_left和P_right。
3.分别在P_left和P_right中递归求解最近点对。
4.在左右两部分求得的最近点对中,选择距离更小的那一对作为候选解。
5.在区间[P_left[-1].x, P_right[0].x]内,查找可能的更近点对。
6.比较候选解与新找到的更近点对,选择距离更小的那一对作为最终解。
3. 算法实现3.1 数据结构在实现最近点对算法时,需要定义合适的数据结构来表示点。
常见的表示方法是使用二维数组或类对象。
以下是使用类对象来表示点的示例代码:class Point:def __init__(self, x, y):self.x = xself.y = y3.2 算法步骤3.2.1 排序首先,将所有点按照横坐标进行排序。
可以使用快速排序或归并排序等算法来实现排序功能。
def sort_points(points):# 使用快速排序按照横坐标进行排序# ...3.2.2 分治求解将排序后的点集平均划分为左右两部分,并递归求解最近点对。
def closest_pair(points):n = len(points)# 如果点集中只有两个点,则直接返回这两个点和它们之间的距离if n == 2:return points, distance(points[0], points[1])# 如果点集中只有三个点,则直接计算出最近点对if n == 3:d1 = distance(points[0], points[1])d2 = distance(points[0], points[2])d3 = distance(points[1], points[2])if d1 <= d2 and d1 <= d3:return [points[0], points[1]], d1elif d2 <= d1 and d2 <= d3:return [points[0], points[2]], d2else:return [points[1], points[2]], d3# 将点集平均划分为左右两部分mid = n // 2P_left = points[:mid]P_right = points[mid:]# 分别在左右两部分递归求解最近点对closest_pair_left = closest_pair(P_left)closest_pair_right = closest_pair(P_right)# 在左右两部分求得的最近点对中,选择距离更小的那一对作为候选解if closest_pair_left[1] < closest_pair_right[1]:min_pair, min_distance = closest_pair_leftelse:min_pair, min_distance = closest_pair_right3.2.3 查找更近点对在区间[P_left[-1].x, P_right[0].x]内,查找可能的更近点对。
0007算法笔记——【分治法】最接近点对问题
问题场景:在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。
在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。
例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这个空间中最接近的一对点。
这类问题是计算几何学中研究的基本问题之一。
问题描述:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
严格地说,最接近点对可能多于1对。
为了简单起见,这里只限于找其中的一对。
1、一维最接近点对问题算法思路:这个问题很容易理解,似乎也不难解决。
我们只要将每一点与其他n-1个点的距离算出,找出达到最小距离的两个点即可。
然而,这样做效率太低,需要O(n^2)的计算时间。
在问题的计算复杂性中我们可以看到,该问题的计算时间下界为Ω(nlogn)。
这个下界引导我们去找问题的一个θ(nlogn)算法。
采用分治法思想,考虑将所给的n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,然后在每个子集中递归地求其最接近的点对。
在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对,因为S1和S2的最接近点对未必就是S的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。
但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n^2/4次计算和比较才能确定S的最接近点对。
因此,依此思路,合并步骤耗时为O(n^2)。
整个算法所需计算时间T(n)应满足:T(n)=2T(n/2)+O(n^2)。
它的解为T(n)=O(n^2),即与合并步骤的耗时同阶,这不比用穷举的方法好。
从解递归方程的套用公式法,我们看到问题出在合并步骤耗时太多。
这启发我们把注意力放在合并步骤上。
设S中的n个点为x轴上的n个实数x1,x2,..,xn。
平面最近点对问题(分治)
平⾯最近点对问题(分治)平⾯最近点对问题是指:在给出的同⼀个平⾯内的所有点的坐标,然后找出这些点中最近的两个点的距离.⽅法1:穷举1)算法描述:已知集合S中有n个点,⼀共可以组成n(n-1)/2对点对,蛮⼒法就是对这n(n-1)/2对点对逐对进⾏距离计算,通过循环求得点集中的最近点对2)算法时间复杂度:算法⼀共要执⾏ n(n-1)/2次循环,因此算法复杂度为O(n2)代码实现:利⽤两个for循环可实现所有点的配对,每次配对算出距离然后更新最短距离.for (i=0 ; i < n ;i ++){for(j= i+1 ; j<n ;j ++){点i与点j的配对}}⽅法2:分治1) 把它分成两个或多个更⼩的问题;2) 分别解决每个⼩问题;3) 把各⼩问题的解答组合起来,即可得到原问题的解答。
⼩问题通常与原问题相似,可以递归地使⽤分⽽治之策略来解决。
在这⾥介绍⼀种时间复杂度为O(nlognlogn)的算法。
其实,这⾥⽤到了分治的思想。
将所给平⾯上n个点的集合S分成两个⼦集S1和S2,每个⼦集中约有n/2个点。
然后在每个⼦集中递归地求最接近的点对。
在这⾥,⼀个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。
如果这两个点分别在S1和S2中,问题就变得复杂了。
为了使问题变得简单,⾸先考虑⼀维的情形。
此时,S中的n个点退化为x轴上的n个实数x1,x2,...,xn。
最接近点对即为这n个实数中相差最⼩的两个实数。
显然可以先将点排好序,然后线性扫描就可以了。
但我们为了便于推⼴到⼆维的情形,尝试⽤分治法解决这个问题。
假设我们⽤m点将S分为S1和S2两个集合,这样⼀来,对于所有的p(S1中的点)和q(S2中的点),有p<q。
递归地在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设 d = min{ |p1-p2| , |q1-q2| } 由此易知,S中最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{q3,p3},如下图所⽰。
求两组点之间的最近点对实验总结
求两组点之间的最近点对实验总结在计算几何学和算法设计中,求两组点之间的最近点对是一个重要且常见的问题。
在这篇文章中,我将从简到繁地探讨这个主题,深入分析求解最近点对的算法,并进行实验总结,以便读者能更深入地理解这一概念。
一、什么是最近点对问题?最近点对问题是指在一个平面上给定n个点,要求在这些点中找到距离最近的两个点。
这个问题在实际中有着广泛的应用,比如计算机视觉中的物体识别、无人驾驶车辆的障碍物检测等都涉及到最近点对的计算。
设计高效的算法来解决最近点对问题具有重要意义。
二、最近点对的暴力解法最简单的方法是通过遍历所有点对,计算它们之间的距离,并找到最小值。
这种暴力解法的时间复杂度为O(n^2),空间复杂度为O(1),虽然简单易懂,但对于大规模的数据集来说效率较低。
三、分治法解决最近点对问题分治法是解决最近点对问题的常见方法,其基本思想是将点集分成两个子集,分别求解最近点对,然后再找出整个点集的最近点对。
在这个过程中需要用到分治、筛选和合并三个步骤。
具体算法流程如下:1. 将点集按照x坐标排序,找到中间线将点集分成左右两个子集。
2. 递归求解左右子集的最近点对。
3. 筛选出距离中线距离小于当前最近距离的点,将它们按照y坐标排序。
4. 在筛选后的点集中,以每个点为中心,向上下各取6个点。
5. 计算这些点之间的距离,更新最近距离。
6. 合并左右子集的结果,得到最终的最近点对。
使用分治法解决最近点对问题的时间复杂度为O(nlogn),效率较高,适用于大规模数据集。
四、实验总结及个人观点在进行最近点对的实验过程中,我发现分治法在处理大规模数据集时具有明显的优势,其算法设计合理、程序实现简单高效。
对于中等规模的数据集,暴力解法也能够得到较好的结果,但对于大规模数据集来说效率明显低于分治法。
我个人认为在解决最近点对问题时,应优先考虑使用分治法,并且可以根据数据规模选择不同的算法来达到更高的效率。
总结来说,求两组点之间的最近点对是一个重要且常见的问题,在实际应用中具有广泛的意义。
求最近点对的随机算法
求最近点对的随机算法分治法求解需O(nlogn)时间,而用随机算法求解可达到O(n)时间。
对于给定的平面上的n个点(x i,y i) (i=1,2,…,n)和一个距离δ,以δ为尺寸可以构造一个(逻辑上的)网格,该网格以(min{x i},min{y j})为网格的最左下点,之后以步长δ不断向右、向上伸展为长方形网格;使得(max{x i},max{y j})也含在其中。
由于所有的点均在长方形网格中,最近点对也必在其中。
对每个尺寸为δ×δ的方格,分别向左向上、向右向上、向左向下、向右向下各扩展一格,可得4个2δ×2δ的方格iΓ(i=1,2,3,4)。
δ2定理:设已知平面上的某两点的距离为δ。
若最近点对中的一个点落在某个δ×δ方格Γδ中,则在上述的4个2δ× 2δ方格iΓ(i=1,2,3,4)中,δ2至少有一个同时含有最近点对的两个点。
推论:若已知平面上的某两点的距离为δ,且算法对长方形网格中每一个2δ×2δ方格中的所有点对,均一一计算其距离,则该算法一定可以找出最近点对。
算法:1、点集S(|S|=n)中随机地取一个子集T,使得|T|=⎣n⎦。
(按随机取样算法的分析,n个中取m个(m≤n)时间为O(n))2、T中所有点对逐一计算距离,求出最近点对距离δ(T)。
(点对数为⎣n⎦(⎣n⎦-1)/2,每个点对计算时间为O(1),故总的计算时间为O(⎣n⎦2)= O(n)。
)3、δ(T)为尺寸构造一个(逻辑上的)长方形网格:令m=⎡(最右边点的x坐标-最左边点的x坐标)/ δ(T)⎤r=⎡(最上边点的y坐标-最下边点的y坐标)/ δ(T)⎤,则长方形的横向共有m格,纵向共有r格。
4、如果m*r≤c*n(c可取2~10,取何值合适后面讨论),则开设一个m×r的指针矩阵P、和一个m×r的计数矩阵Q,然后逐一扫描S中的点s k:如果s k落在方格ijδΓ中(i,j分别表示所在方格横向、纵向位置),则把该点放入P[i,j]所指的链表内,Q[i,j]增1,直至n个点全部检查为止。
【精品】最近点对问题
【精品】最近点对问题点对问题是计算机科学中常见的算法问题,也称为最近点对问题。
其目标是在给定一组点的集合中找到最近的两个点。
在这个问题中,我们将使用分治法来解决最近点对问题。
算法的基本思想是将点集按照x坐标进行排序,并将其分成两个子集。
然后,我们对每个子集递归地应用算法,直到子集中只有一个或两个点。
在这种情况下,我们可以直接计算出最近的点对。
然而,当子集中有超过两个点时,我们需要将问题分解成更小的子问题。
我们选择一个中间点,将点集分成两个子集,并计算出每个子集中的最近点对。
然后,我们需要考虑横跨两个子集的点对。
我们使用一个辅助函数来计算两个子集中的最近点对,并返回最小距离。
在计算最近点对时,我们需要考虑两个子问题。
首先,我们需要找到两个子集中的最近点对。
其次,我们需要找到横跨两个子集的最近点对。
为了找到两个子集中的最近点对,我们可以使用递归地应用相同的算法。
我们将两个子集分别按照y坐标进行排序,并计算出每个子集中的最近点对。
然后,我们需要考虑两个子集之间的点对。
我们将点集中的点按照y坐标进行排序,并找到一个以中间点为中心,距离中间点小于最小距离的点集。
然后,我们可以使用一个循环来比较这些点对,并计算出最小距离。
在计算横跨两个子集的最近点对时,我们需要考虑两个子集之间的点对。
我们将点集中的点按照y坐标进行排序,并找到一个以中间点为中心,距离中间点小于最小距离的点集。
然后,我们可以使用一个循环来比较这些点对,并计算出最小距离。
最后,我们将上述步骤的结果与之前计算的最小距离进行比较,选择较小的距离作为最终的最近点对。
分治法是解决最近点对问题的一个有效方法。
它通过将问题分解成更小的子问题,然后递归地解决这些子问题,最终得到整个问题的解。
在最近点对问题中,我们通过将点集按照x坐标和y坐标进行排序,并使用分治法找到最近点对。
通过使用分治法,我们可以在O(nlogn)的时间复杂度内解决最近点对问题。
这使得它成为处理大规模数据集的理想选择。
最接近点对问题_分治法
最接近点对问题_分治法⼀、问题描述给定平⾯上的n个点,找其中的⼀对点,使得在n个点组成的所有点对中该点对间的距离最⼩。
⼆、解题思路及所选算法策略的可⾏性分析思路:利⽤分治法来解决问题。
递归⼦结构求最接近点对总体可分为⼏个步骤:1、当问题规模⼩于20,直接求解最⼩点对2、将n个点组成的集合S分成2个⼦集S1和S23、递归求出两个⼦集中的最接近点对并⽐较出最⼩点对,记录距离dmin4、以X坐标为基准找到所有点中线,在中线附近找出相距可能⼩于dmin的点对点,记录于S3和S45、求S3和S4每点对距离,和dmin进⾏⽐较,求解最接近点对策略可⾏性分析:设直线l上有2m个点,以m为中点将l分割成两条线段dl,dr,然后求出dl和dr这两点条线段中的最⼩点距d1,d2,此时d=min{d1,d2},再通过计算出dl线段的中最⼤点与dr线段中的最⼩点之间的距离D,最⼩距离则为min{d,D}.⼆维情况与此相似,最⼤的区别只是对于中线位置的点,⼆维情况只是针对中线旁好多可能点,再在Y轴⽅向上进⾏点的筛选,以减少平⽅计算次数。
三、伪代码描述及复杂度分析Public static double closestPoint(S){1、⾸先,递归结束条件,当数组长度在⼀定范围内时直接求出最近点,蛮⼒求解2、求所有点在X坐标中的中位数midX3、以midX为界将所有点分成两组分别存放在两个表中4、将两张表转化为数组类型,并分别按X坐标升序排列5、求S1中的最近距离的两个点6、求S2中的最近距离的两个点7、求两最近距离的最⼩值8、在S1、S2中收集距离中线⼩于d1的点,分别存放于两个表中9、分别将表T3、T4转换为数组类型的S3、S4,并将其分别按Y坐标升序排列10、求解S3、S4两者之间可能的更近(相⽐于d1)距离 , 以及构成该距离的点}复杂度分析:设算法耗时T(n)。
算法第1步、第2步、第3步和第8步⽤了O(n)时间。
分治 最近点对 证明过程
分治最近点对证明过程分治算法是一种将问题分解为更小的子问题,并通过递归解决子问题,最后将子问题的解合并起来得到原问题解的方法。
最近点对问题是指在一个给定的点集中,找到距离最近的两个点的问题。
在本文中,我们将使用分治算法来解决最近点对问题,并对其正确性进行证明。
我们需要明确最近点对问题的定义。
给定一个点集P,我们需要找到其中两个点p和q,使得它们的距离d(p,q)最小。
距离可以使用欧氏距离或其他度量方式来定义。
我们的目标是设计一个高效的算法来解决这个问题。
分治算法的基本思想是将问题分解为更小的子问题,并通过递归解决子问题。
在最近点对问题中,我们可以将点集P划分为两个较小的子集P1和P2,分别包含点集P的前一半和后一半的点。
然后,我们分别在P1和P2中递归地找到最近点对。
假设在P1和P2中分别找到的最近点对是(p1,q1)和(p2,q2)。
接下来,我们需要考虑P1和P2之间的最近点对。
我们可以观察到,P1和P2中的点到分割线的距离不能超过d1和d2,其中d1和d2分别是P1和P2中找到的最近点对的距离。
因此,我们只需要考虑距离分割线小于d的点。
我们可以将P1和P2按照x轴坐标排序,并找到中间点mid。
然后,我们可以构建一个矩形区域,将其划分为两个部分,分别包含P1和P2的点。
我们只需要在这个矩形区域中找到距离分割线小于d 的点对。
在这个矩形区域中,我们可以按照y轴坐标排序点,并使用滑动窗口的方法来找到距离最近的点对。
具体来说,我们可以从矩形区域的顶部开始,依次考虑每个点,并计算它与后面d/d2个点的距离。
如果找到了距离更小的点对,则更新最近点对的距离。
我们将在P1、P2和跨越分割线的点中找到最近的点对,并返回其距离。
通过以上步骤,我们可以使用分治算法来解决最近点对问题。
接下来,我们将证明该算法的正确性。
我们可以观察到,如果两个点p和q是最近点对,并且它们在分割线的同一侧,那么它们必定在P1或P2中。
分治法解最接近点对问题
算法分析与设计实验报告2014-2015第一学期实验一:用分治法解最接近点对问题指导教师:cccc实验时间:2014年10月28日实验地点:计算中心二楼班级:计ccc学号: 124cc08姓名:杨cc 成绩:实验一用分治法解最接近点对问题的实验一、实验内容:实践名称:用分治法解最接近点对问题的实验时间安排:3学时一、实验目的通过上机实验,要求掌握分治法的问题描述、算法设计思想、程序设计和算法复杂性分析等。
二、实验环境装有Visual C++6.0的计算机。
本次实验共计3学时。
三、实验内容1、熟悉分治算法思想掌握如何创建应用程序。
掌握对最接近点对问题描述,及如何运用算法策略对问题解决和实现。
2、掌握如何编译程序理解编译过程中的错误信息,并掌握如何排错。
3、掌握如何调试程序掌握如何通过设置断点来单步调试程序,如何查看当前变量的值。
4、实验题:完成用分治法解最接近点对问题的实验。
要求:实现该实验结果。
通过该实验题,解决最接近点对问题。
二、实验报告要求1、报告内容包括实验目的、实验内容、实验步骤,实验结果和心得体会五部分;其中实验步骤包括算法分析、算法设计、算法实现主要步骤。
2、截止时间统一为下周二前。
1)算法分析问题描述:已知集合S中有n个点,求这些点中最近的两个点的距离算法分析:分治法的思想就是将S进行拆分,分为2部分求最近点对。
将S拆分左右两部分为SL和SR,L一般取点集S中所有点的中间点的x坐标来划分,这样可以保证SL和SR中的点数目各为n/2,依次找出这两部分中的最小点对距离:δL和δR,记SL和SR中最小点对距离δ = min(δL,δR)以L为中心,δ为半径划分一个长带,最小点对还有可能存在于SL和SR的交界处,如下图2左图中的虚线带,p点和q点分别位于SL和SR的虚线范围内,在这个范围内,p点和q点之间的距离才会小于δ,最小点对计算才有意义。
figure 2对于SL虚框范围内的p点,在SR虚框中与p点距离小于δ的顶多只有六个点,就是图二右图中的2个正方形的6的顶点。
最近点对问题
算法分析与设计最近对问题最近对问题问题描述:在二维平面上的n 个点中,如何快速的找出最近的一对点,就是最近点对问题。
程序设计思想:1.蛮力法求最近对问题:基本思想:分别计算每一对点之间的距离,然后找出距离最小的那一对,为了避免对同一对点计算两次距离,只考虑j i <的那些点对()j i P P ,。
复杂度分析:对于此算法,主要就是算两个点的欧几里得距离。
注意到在求欧几里得距离时,避免了求平方根操作,其原因是:如果被开方的数越小,则它的平方根也越小。
所以复杂度就是求平方,求执行次数为: )()1()(2n O n n n T =-=;即时间复杂度为)(2n O 。
2.分治法求最近对问题:基本思想:用分治法解决最近点对问题,就是将一个问题分解两个子问题,然后递归处理子问题,然后合并。
可能两个点在每个子问题中,也可能两个点分别在两个子问题中,就这两种情况。
则基本过程为:找一条中垂线m (坐位S 集合x 坐标的中位数)把n 个元素分成左右两部分元素,然后分别求得两边的最短距离1d ,2d ,然后取两者中的最小者记为d ,在中线两边分别取d 的距离,记录该距离范围内点的个数,中线左边有L 个元素,右边有R 个元素,分别将两边的点按y 坐标升序排列,在左边集合中每一个点,找右边集合的点,找到与之距离小于d 的点,更新最短距离,直到循环结束,即可求出最短距离。
复杂度分析:应用分治法求解含有n 个点的最近对问题,其时间复杂性可由递推式表示:)()2/(*2)(n f n T n T +=。
由以上分析:合并子问题的解的时间)1()(O n f =。
进而可得分治法求最近对问题的时间复杂度为:)log ()(2n n O n T =。
程序代码:#include <stdio.h>#include <stdlib.h>#include <math.h>#define NUM 1000typedef struct{int x;int y;}N;double distance(N n1,N n2);double minDis(double d1,double d2);double shortestDis(N *data,int length,N *n1 , N *n2); double shortestDis(N *data,int length,N *n1 , N *n2){ int pre,last,middle,median;int i,c1num = 0,c2num = 0,j;N* dataP;N* dataL;N* CP;N* CL;N tn1,tn2;double dis1 ,dis2;// 当只有两个点时,返回最短距离,和点if(length == 2 ){double dis1 = distance(data[0],data[1]);*n1 = data[0];*n2 = data[1];return dis1;}else if(length == 3){// 当只有三个点时,返回最短距离,和点double dis1 = distance(data[0],data[1]);double dis2 = distance(data[1],data[2]);double dis3 = distance(data[0],data[2]);double temp;temp = dis1 < dis2 ? dis1:dis2;temp = temp < dis3 ? temp : dis3;if(temp == dis1){*n1 = data[0];*n2 = data[1];}else if(temp == dis2){*n1 = data[1];*n2 = data[2];}else{*n1 = data[0];*n2 = data[2];}return temp;}middle =length/2;pre = middle;last = length - pre;median = data[middle].x; // 记录中位数dataP = (N*)malloc(sizeof(N)*pre);dataL = (N*)malloc(sizeof(N)*last);CP = (N*)malloc(sizeof(N)*pre);CL = (N*)malloc(sizeof(N)*last);for( i = 0;i < pre ;i++)dataP[i] = data[i];for( i = 0; i< last;i++)dataL[i] = data[i+pre];dis1 = shortestDis(dataP , pre , n1 , n2);dis2 = shortestDis(dataL , last , &tn1 , &tn2);if(dis1 > dis2){*n1 = tn1;*n2 = tn2;}dis1 = minDis(dis1,dis2);for( i = 0; i < pre ; i++)if(dataP[i].x - median < dis1){CP[c1num++] = dataP[i];} // 将在中位数之前的区域中与中位数距离小于最短距离的点放到CP 中for( i = 0; i < last ; i++)if(median - dataL[i].x < dis1){CL[c2num++] = dataL[i];}// 将在中位数之后的区域中与中位数距离小于最短距离的点放到CL 中for(i = 0; i< c1num;i++){for( j =0; j < c2num ; j++){double temp = distance(CP[i],CL[j]);if(temp < dis1){dis1 = temp;*n1 = CP[i];*n2 = CL[j];}}}//依次计算中位数两旁的区域中,每一个点与另外一个区域中的距离,并且记录最短距离return dis1;}double distance(N n1,N n2){return sqrt((n1.x -n2.x)*(n1.x -n2.x) + (n1.y - n2.y)*(n1.y - n2.y));}double minDis(double d1,double d2){double d = d1 < d2 ? d1 : d2;return d;}// 分治法排序void MergeSort(N q[],int num,int mode){int i,nump,numl;N* qPre;N* qLast;if(num == 1 )return;if(num%2&&num != 2){numl = num/2;nump = num/2;nump++;}else{numl = num/2;nump = num/2;}qPre = (N*)malloc(sizeof(N)*nump);qLast = (N*)malloc(sizeof(N)*numl);for(i = 0;i < nump;i++)qPre[i] = q[i];for(i = 0;i<numl;i++)qLast[i] = q[nump+i];MergeSort(qPre,nump,mode);MergeSort(qLast,numl,mode);Merge(qPre,qLast,q,nump,numl,mode);}void Merge(N *pre,N *last,N *total,int nump,int numl,int mode){ int i = 0,j = 0,k = 0;while( i< nump && j< numl ){if(mode == 0){if(pre[i].x > last[j].x ){total[k++] = pre[i++];}else{total[k++] = last[j++];}}else{if(pre[i].y > last[j].y ){total[k++] = pre[i++];}else{total[k++] = last[j++];}}}if(i == nump){for(i = j; i < numl; i++)total[k++] = last[i];}else{for(j = i; j < nump; j++)total[k++] = pre[j];}}void computeShortestDistance(N* data , int num ,int result[4]){FILE *fo;int i,j,l = 0;int *datax,*datay;double dis = 666666,temp;datax = (int*)malloc(sizeof(int)*1000);datay = (int*)malloc(sizeof(int)*1000);for(i =0; i<num ;i++){datax[i] = data[i].x;datay[i] = data[i].y;}for(i = 0;i<num;i++){for(j = i+1;j<num;j++)if((temp = (datax[i] - datax[j])*(datax[i] - datax[j]) + (datay[i] - datay[j])*(datay[i] - datay[j])) < dis){dis = temp;result[0] = datax[i];result[1] = datay[i];result[2] = datax[j];result[3] = datay[j];}}printf("\n蛮力法:\n");printf("shortest dis: %f",sqrt(dis));}void generateDots(int number){FILE *fo;int i,n1,n2;if(!(fo = fopen("data.txt","w"))){printf("open file fail");exit(1);}for(i = 0;i< number;i++){srand((i*i));n1 =rand()%8000;srand(time(NULL)*i*i);n2 = rand()%6000;if(i%2)fprintf(fo,"%d %d\n",n1,n2);elsefprintf(fo,"%d %d\n",n2,n1);}fclose(fo);}int main(){ FILE* fo;N* data;int i;N n1,n2;double dis;int re[4];// 生成数据generateDots(NUM);data = (N*)malloc(sizeof(N)*1000);if(!(fo = fopen("data.txt","r"))){printf("open file fail");exit(1);}for(i = 0;i < NUM;i++){fscanf(fo,"%d %d",&data[i].x,&data[i].y);}fclose(fo);// 合并排序,排好序的数据放置到data 中。
二维空间求最近点对算法模板
二维空间求最近点对算法模板(分治法)选取一垂直线l:x=m来作为分割直线。
其中m为S中各点x坐标的中位数。
由此将S分割为S1和S2。
递归地在S1和S2上找出其最小距离d1和d2,并设d=min{d1,d2},S中的最接近点对或者是d,或者是某个{p,q},其中p∈P1且q∈P2 ,如图所示。
能否在线性时间内找到p,q?考虑P1中任意一点p,它若与P2中的点q构成最接近点对的候选者,则必有distance(p,q)<d。
满足这个条件的P2中的点一定落在一个d×2d的矩形R 中,如图所示。
由d的意义可知,P2中任何2个S中的点的距离都不小于d。
由此可以推出矩形R中最多只有6个S中的点。
证明:将矩形R的长为2d的边3等分,将它的长为d的边2等分,由此导出6个(d/2)×(2d/3)的矩形(如图(a)所示)。
若矩形R中有多于6个S中的点,则由鸽舍原理易知至少有一个(d/2)×(2d/3)的小矩形中有2个以上S中的点。
设u,v是位于同一小矩形中的2 个点,则因此,distance(u,v)<d。
这与d的意义相矛盾。
也就是说,矩形R中最多有6个S中的点。
极端情形:图(b)是矩形R中恰有6个S中的点的极端情形。
因此,在分治法的合并步骤中最多只需要检查6×n/2=3n个候选者。
为了确切地知道要检查哪6个点,可以将p和P2中所有S2的点投影到垂直线l 上。
由于能与p点一起构成最接近点对候选者的S2中点一定在矩形R中,所以它们在直线l上的投影点距p在l上投影点的距离小于d。
由上面的分析可知,这种投影点最多只有6个。
因此,若将P1和P2中所有S中点按其y坐标排好序,则对P1中所有点,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者。
对P1中每一点最多只要检查P2中排好序的相继6个点。
算法描述:public static double CPair2(S){n=|S|;if (n < ; 2) returnm=S中各点x间坐标的中位数;构造S1和S2;//S1={p∈S|x(p)<=m},S2={p∈S|x(p)>m}d1=cpair2(S1);d2=cpair2(S2);dm=min(d1,d2);设P1是S1中距垂直分割线l的距离在dm之内的所有点组成的集合;模板程序:#include <iostream>#include <algorithm>#include <cmath>using namespace std;#define MAXN 100000struct node{ double x,y; }point[MAXN];//存放点的结构体数组bool cal_less(node p1,node p2){ if(p1.x != p2.x) return p1.x < p2.x; else return p1.y < p2.y; }double dist(node a, node b){ return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y)); }double getmin(double a, double b){ return a<b?a:b; }double solve(int l,int r){ if(l == r) return 1000000000;if(l == r - 1) return dist(point[l],point[r]);if(l == r - 2) returngetmin(getmin(dist(point[l],point[l+1]),dist(point[l+1],point[l+2])),dist(point[l],point[l+2]));int i,j,mid = (l+r) >> 1;double curmin = getmin(solve(l,mid),solve(mid+1,r));for(i=l;i<=r;i++)for(j=i+1;j<=i+5 && j<=r;j++){ curmin = getmin(curmin,dist(point[i],point[j])); }return curmin;}//入口函数,n代表点的个数double ClosestPairDistance(int n){ sort(point,point+n,cal_less);return solve(0,n-1);}。
最近点对算法 C++
实验三最近点对1.算法设计思路:设共有n个点,找其中距离最近的两点及其距离。
(1)蛮力法:蛮力法的思路是把所有点之间距离比较找出中间最小的。
先假设最短距离是第一个元素和第二个元素的距离,然后求第一个元素与其后的(n-1)个元素各自的距离,若比之前记录的最短距离小则记录当前值···求第i个元素与其后的(n-i)个元素各自的距离,记录之前所得到的所有距离中的最小值,直到计算到第(n-1)个元素与第n个元素的距离,此时记录的距离即为这n个元素中的最短距离。
(2)分治法:分治法是把一个大的问题划分成相似的小问题,采用递归的思想。
找中线把n个元素分成左右两部分元素分别求得两边的最短距离,然后取两者中的最小者记为l,在中线两边分别取l的距离,记录该距离范围内点的个数,中线左边有L个元素,右边有R个元素,求左边元素到右边元素的距离看其是否小于之前记录的最短距离,小则记录下来,此时的右边元素只取y值和左边元素y值距离小于l的(减少循环次数)。
循环结束即可找到最小的距离。
2.程序代码:#include<iostream>#include<cstdlib>#include<ctime>#include<cmath>using std::cout;using std::endl;#define N 5int x[N],y[N],record[N]; //产生原始点数据,x坐标放在x[]中,y坐标放在y[]中。
double Min;//////////////////////////产生随机数组/////////////////////////////void randnum(){int i;srand(time(0));for (i=0;i<N;i++){x[i]=rand()%N;cout<<x[i]<<' ';}cout<<endl;for (i=0;i<N;i++){y[i]=rand()%N;cout<<y[i]<<' ';}cout<<endl;}//////////////////////////////交换数组元素/////////////////////////// void swap(int & a, int & b){int temp=a;a=b;b=temp;}///////////////////////////////求平方///////////////////////////////////int square(int x){return x*x;}/////////////////////////////////////求两点之间距离////////////////////double lengthf(int x1,int y1,int x2,int y2){return sqrt(square(x1-x2)+square(y1-y2));}//////////////////////////////////求两者中最小者////////////////////// double min(double a,double b){if (a>=b)return b;elsereturn a;}////////////////////////////对平面数组排序//////////////////////////// void sort(int A[]){int i,j;for (i=0;i<N;i++)record[i]=i;for (j=1;j<N;j++){i=j;while (i>=0&&A[i]<A[i-1]){swap(A[i],A[i-1]);swap(record[i-1],record[i]); //得到x排序后对应的原y的坐标i--;}}cout<<"排序后的元素数组:"<<endl;for (i=0;i<N;i++)cout<<A[i]<<' ';cout<<endl;for (i=0;i<N;i++)cout<<record[i]<<' ';cout<<endl;}///////////////////////////穷举法找最小点对///////////////////////////////double exhaustion(){int i,j,k1,k2;double num;double length;num=10000;k1=k2=-1;for (j=0;j<N-1;j++){for (i=j+1;i<N;i++){length=lengthf(x[i],y[i],x[j],y[j]);if (length<num){num=length;k1=i;k2=j;}}}cout<<"平面数组最短距离是:"<<endl;cout<<"min="<<num<<endl;cout<<"对应数组下标及点坐标为:"<<endl;cout<<"i="<<k1<<','<<k2<<endl;cout<<"(x1,y1)="<<'('<<x[k1]<<','<<y[k1]<<')'<<endl<<"(x2,y2)="<<'('<<x[k2]<<','<<y[k2]<<')' <<endl;return num;}////////////////////////////////////分治法////////////////////////////////*************************************************************************/double merge(int left,int right){double mlength;if (right==left)mlength=10e-6;if (right==left+1)mlength=lengthf(x[right],y[record[right]],x[left],y[record[left]]); //两个点时求最小值if (right-left==2)mlength=min(min(lengthf(x[right-1],y[record[right-1]],x[left],y[record[left]]),lengthf(x[right],y[re cord[right]],x[left+1],y[record[left+1]])),lengthf(x[right],y[record[right]],x[left],y[record[left]]));//三个点时求最大值return mlength;}double divide(int left,int right){if (right-left<=2){Min=merge(left,right);}else{double l1,l2,mi; //l1记录划分区域后左半面最小距离,l2记录右半面最小距离,min为两者中较小者,m为全部中的最小者int rem1,rem2,l; //记录获得最短距离对应的两个点//int il,jl,ir,jr;int i,j;int R,L;R=L=0; //记录划分小区域后的左半块和右半块个有多少元素l1=l2=Min=100;l=(right-left+1)/2-1; //中线位置///////////////////////////////////////////////////l1=divide(left,l);l2=divide(l+1,right);if (l1<l2){Min=l1;//cout<<"两半面最短距离是:"<<min;else{Min=l2;//cout<<"两半面最短距离是:"<<min;}///////////////////得到右半块元素数R//cout<<"min="<<min<<endl;for (i=l+1;i<N;i++){if (x[i]-x[l]<=Min)R++;else break;}//cout<<"R="<<R<<endl;/////////////////////得到左半块元素数Lfor (i=l;i>=0;i--){if (x[l]-x[i]<=Min)L++;else break;}//cout<<"L="<<L<<endl;if (L!=0&&R!=0){for (i=l-L+1;i<=l;i++)for (j=l+1;j<=l+R;j++){if (y[record[j]]-y[record[i]]<Min||-Min<y[record[j]]-y[record[i]]){mi=lengthf(x[i],y[record[i]],x[j],y[record[j]]);if (mi<Min){Min=mi;rem1=i;rem2=j;}}}// cout<<"min="<<min<<endl;//cout<<"rem1="<<rem1<<endl<<"rem2="<<rem2<<endl;}return Min;}/***********************************************************************///////////////////////////////////主函数///////////////////////////////////int main(){//double a;randnum();cout<<"***************************遍历法*************************"<<endl;exhaustion();cout<<"***************************分治法*************************"<<endl;sort(x);divide(0,N-1);cout<<"元素组中最短距离为:"<<endl;cout<<"min="<<Min<<endl;return 0;}3.实验数据及实验结果:实验数据:随机产生的五个点坐标分别为:(1,3),(4,2),(3,0),(2,0),(0,3)实验结果:用蛮力法得到平面数组最短距离为:min=1用分治法得到平面数组最短距离为:min=14.实验总结:从本次试验中得到的领悟是:分治法事把问题分解成两个相似小问题,子问题和原来的大问题解决方法一样所以可以用递归,分治法重要是找到递归出口,什么时候递归结束,一般都有元素个数的限制。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。
若知道任意两个洞的最小距离,可估计金属断裂的概率。
这种最小距离问题实际上也就是距离最近的点对问题。
如果不用分治法,问题非常容易解决。
也就是蛮力法。
代码如下:#include <stdio.h>#include <math.h>typedef struct TYPE{double x, y;} Point;float dist(Point a,Point b){return (float)sqrt((float)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}float nearest(Point* points, int n) {float temp,near1=10000;int i,j;if(n==1) {printf("不可能");return 0;}else{for(i=0; i<n-1; i++)for(j=i+1; j<n; j++){{temp=dist(points[i],points[j]);near1=(near1>temp)?temp:near1;}}return near1;}}int main(){int n, i;double d;printf("输入点的个数:");scanf("%d", &n);Point a[10000];while (n){for (i = 0; i < n; i++)scanf("%lf%lf", &(a[i].x), &(a[i].y));d = nearest(a,n);printf("%.2lf\n", d);scanf("%d", &n);}return 0;}但是本题是用分治法,我也参考了网上很多资料,他们要求对纵坐标进行排序,可能是为了对求右边的问题的点扫描用for 循环,但我发现那算法就不对,但愿是我的还没有完全明白按纵坐标排序的原因,我参考的资料:/p-198711591.html?qq-pf-to=pcqq.c2c 代码如下:#include <stdio.h>#include <stdlib.h>#include <math.h>#define MAX_POINTS 100000 /*坐标点数的最大值*/#define MAX_TEST 100 /*最大测试次数*/typedef struct { /*定义坐标点*/float x;float y;}Point;float dist(Point a, Point b) { /*求两个坐标点之间的距离*/returnsqrt((float)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}float Nearest(Point* points, int n){ /*求最小距Nearest的函数*/float temp1,temp2,temp3,temp,nearest;float left,right,d;int i,j;if(n==1) printf("距离为0"); /*一个点情形,返回值模拟0。
也可以用retrun 0来代替*/if(n==2) return dist(points[0], points[1]); /*两个点情形,调用dist函数*/if(n==3){ /*三个点情形时,分别计算出距离,然后两两比较*/temp1=dist(points[0], points[1]);temp2=dist(points[0], points[2]);temp3=dist(points[1], points[2]);returntemp3<((temp1<temp2)?temp1:temp2)?temp3:((temp1<tem p2)?temp1:temp2);}/*多于3点的情形,用分治法*/left=Nearest(points,n/2); /*递归求解求左边点对的最小距离*/right=Nearest(&points[n/2],n-n/2); /*递归求解求右边点对的最小距离*/d=left<right?left:right;/*综合中间带求得最小距离*///将P1和P2中所有S的点按其x坐标排好序,则对P1中所有点p,//对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,//对P1中每一点最多只要检查P2中排好序的相继6个点。
nearest=d;for(i=0;i<n/2;i++)/* 通过扫描子集一中每个点检查子集二中与其距离在d之内的所有点(最多6个)以完成合并*/for(j=n/2;j<n&&(fabs(points[j].y-points[i].y)<d);j++){ //跨场地的点对的y轴值的差的绝对值与d比较temp=dist(points[i],points[j]);nearest=nearest<temp?nearest:temp;}return nearest;}int compx(const void* a, const void* b) { //定义比较函数,常量指针const指向的区域*a,*b不可修改,大于,返回>0;小于,返回<0;相等,返回0/*实现按x排序*/return ((Point*)a)->x-((Point*)b)->x;}int compy(const void* a, const void* b) { /*实现按y排序*/return ((Point*)a)->y-((Point*)b)->y;}void main() {int i,j=0,numPoints;Point points[MAX_POINTS];//类point的数组,用来存放点对float result[MAX_TEST]; /*定义一个每次测试结果的数组*/for(i=0;i<MAX_TEST;i++) result[i]=-1;//初始化测试结果,全部设置为-1printf("请输入数据:\n");while(1){ /*进行多次测试*/ loop: printf("请输入你要在金属板上钻孔的个数:");scanf("%d", &numPoints);if(!numPoints) break;//如果输入点数0,跳出循环if(numPoints<0||numPoints>MAX_POINTS) {printf("非法输入,请重新输入点的个数!\n"); /*报错!*/goto loop;}printf("请依次输入各圆孔中心点的x,y坐标:\n");for(i=0; i<numPoints; i++) { /*输入点的数量及点的坐标值*/printf("请输入第%d个圆孔中心点的x,y轴坐标:",i+1);scanf("%f %f", &points[i].x, &points[i].y);printf("\n");}/*预先将S中的n个点依其x坐标排序好,方便画出中间线,使得场地点数大致相等。
*/qsort(points, numPoints, sizeof(Point), compx);//compx为指针,是指向compx函数,用于确定排序的顺序//编译器函数库自带的快速排序函数qsort(points, numPoints/2, sizeof(Point), compy);//对y轴点对上半部分排序qsort(points+numPoints/2,numPoints-numPoints/2,sizeof(Poin t),compy);//对y轴点对下半部分排序result[j]=Nearest(points, numPoints);j++;//j加1,表示记录了该次结果后,再在数组result[]中记录下次的测试结果}i=0;//输入点数为0个时,就输出结果printf("两圆孔中心的最短距离为:\n");while(result[i]!=-1) /*不为-1时(因为此时已经有了实际的结果,就输出多次测试的结果*/printf("%.4f\n",result[i++]);}他的算法是有问题的:假设点是(-5,2),(-3,-2),(-0.5,-100)和点(0,1)得到的最近点对距离是4.47所以我就没有点的纵坐标进行排序,而且输出了,在分治法中找出并输出满足左边的点的时候,同时也输出满足右边的点。
代码如下:#include <iostream>#include<cmath>using namespace std;const int N = 100005;const double eps = 0.00001;typedef struct TYPE /*定义坐标点*/{double x, y;} Point;Point a[N];double closest(Point *, int); //求点队中最近点对的距离double dis(Point, Point); //求二点间的距离int cmp_x(const void *, const void*);double min(double, double); //二者中的小者int main(){int n, i;double d,dist;printf("输入金属板能接受的最小距离:");scanf("%lf", &dist);printf("输入钻孔的点的个数:"); //输入点的个数scanf("%d", &n);while (n) //用循环给n个点赋予横,纵坐标值{for (i = 0; i < n; i++)scanf("%lf%lf", &(a[i].x), &(a[i].y));qsort(a, n, sizeof(a[0]), cmp_x); //编译器函数库自带的快速排序函数//输出按横坐标排序后的点对printf("输出按横坐标排序后的点\n");for( i=0;i<n;i++)printf("%.2lf %.2lf\n",a[i].x,a[i].y);d = closest(a, n); //调用求点对中的最小距离printf("所有点对中最近点的距离:%.2lf\n", d); //输出最近点对的距离if(d<dist)printf("金属板可能会断掉。