最接近点对问题
蛮力法和分治法的性能比较

蛮力法与分治法求解最近对问题1、蛮力法蛮力法是一种简单直接地解决问题的方法,常常直接基于问题的描述和所涉及的概念定义,来求解问题。
虽然巧妙和高效的算法很少来自于蛮力法,但它仍是一种重要的算法设计策略:(1)适用泛围广,是能解决几乎所有问题的一般性方法;(2)常用于一些非常基本、但又十分重要的算法(排序、查找、矩阵乘法和字符串匹配等);(3)解决一些规模小或价值低的问题;(4)可以做为同样问题的更高效算法的一个标准;(5)可以通过对蛮力法的改进来得到更好的算法。
2、分治法分治法,就是分而治之即把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题直到问题解决。
分治法在求解问题时,效率比较高,也是一种重要的算法策略:(1)该问题的规模缩小到一定的程度就可以容易地解决;(2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;(3)利用该问题分解出的子问题的解可以合并为该问题的解;(4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
算法的基本思想及复杂度分析1.蛮力法(1)基本思想蛮力法求解最近对问题的过程是:分别计算每一对点之间的距离,然后通过排序找出距离最小的一对,为了避免对同一对点计算两次距离,只考虑i<j的那些点对(P i,P j)。
(2)复杂度分析算法的基本操作是计算两个点的欧几里得距离。
在求欧几里得距离时,我们要避免求平方根操作,因为求平方根时要浪费时间,而在求解此问题时,求解平方根并没什么更大的意义。
如果被开方的数越小,则它的平方根也越小。
因此,算法的基本操作就是求平方即可,其执行次数为:T(n)=∑-=11n i ∑+=n i j 12 =2∑-=-11)(n i i n =n (n-1)=O (n2)2.分治法(1)基本思想用分治法解决最近对问题,就是将集合S 分成两个子集S1和S2,每个子集中有n/2个点。
计算机算法设计与分析(第4版)[王晓东][电子教案]第2章
![计算机算法设计与分析(第4版)[王晓东][电子教案]第2章](https://img.taocdn.com/s3/m/6ef58047f7ec4afe04a1df38.png)
2.1 递归的概念
例5 整数划分问题 前面的几个例子中,问题本身都具有比较明显的递归关系,因 而容易用递归函数直接求解。 在本例中,如果设p(n)为正整数n的划分数,则难以找到递归关 系,因此考虑增加一个自变量:将最大加数n1不大于m的划分个 数记作q(n,m)。可以建立q(n,m)的如下递归关系。
A(1,0) 2 A(0, m) 1 m0 A(n,0) n 2 n2 A(n, m) A( A(n 1, m), m 1) n, m 1
2.1 递归的概念
例3 Ackerman函数 前2例中的函都可以找到相应的非递归方式定义:
n! 1 2 3 (n 1) n
T(n)
n/2
=
n/2
n
n/2 n/2
T(n/4)T(n/4)T(n/4)T(n/4) T(n/4)T(n/4)T(n/4)T(n/4) T(n/4)T(n/4)T(n/4)T(n/4) T(n/4)T(n/4)T(n/4)T(n/4
算法总体思想
将求出的小规模的问题的解合并为一个更大规模的问 题的解,自底向上逐步求出原来问题的解。
1 q ( n, n ) q ( n, m ) 1 q (n, n 1) q ( n, m 1) q (n m, m)
正整数n的划分数p(n)=q(n,n)。
n 1, m 1 nm nm n m 1
2.1 递归的概念
例6 Hanoi塔问题 设a,b,c是3个塔座。开始时,在塔座a上有一叠共n个圆盘,这 些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号 为1,2,…,n,现要求将塔座a上的这一叠圆盘移到塔座b上,并仍 按同样顺序叠臵。在移动圆盘时应遵守以下移动规则: 规则1:每次只能移动1个圆盘; 规则2:任何时刻都不允许将较大的圆盘压在较小的圆盘之上; 规则3:在满足移动规则1和2的前提下,可将圆盘移至a,b,c中 任一塔座上。
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中的点。
分治算法

65 97
13 76
38 49 65 97
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归 调用
49 38 65 97 76 13 27
38 49
65 97
13 76
27
38 49 65 97
题的解,自底向上逐步求出原来问题的解。
T(n)
=
n
递归的概念
由分治法产生的子问题往往是原问题的较小模式,这 就为使用递归技术提供了方便。在这种情况下,反复 应用分治手段,可以使子问题与原问题类型一致而其 规模却不断缩小,最终使子问题缩小到很容易直接求 出其解。这自然导致递归过程的产生。
直接或间接地调用自身的算法称为递归算法。用函数 自身给出定义的函数称为递归函数。
黑盒划分典型问题—合并排序
【例5】合并排序
任务描述:任意给定一包含n个整数的集合,把n个整数按升序排列。 输入:每测试用例包括两行,第一行输入整数个数,第二行输入n个整 数,数与数之间用空格隔开。最后一行包含-1,表示输入结束。 输出:每组测试数据的结果输出占一行,输出按升序排列的n个整数。 样例输入:
13 27 76
13 27 38 49 65 76 97
黑盒划分典型问题—合并排序
黑盒划分典型问题—合并排序
合并排序算法改进
从分治过程入手,容易消除mergeSort算法中的递归调用 自然合并排序
49 38 65 97 76 13 27
49
38 65 97
76
13 27
38 49 65 97
黑盒划分典型问题—逆序对问题
矩阵连乘问题

宁波工程学院电信学院计算机教研室实验报告一、实验目的:通过上级实验,要求掌握动态规划算法的问题描述,算法设计思想,程序设计和算法复杂性分析等。
二、实验环境:VC6.0三、实验内容:1、用分治法算法解决最接近点对问题(1)问题的描述给定n个矩阵{nAAA ,2,1},其中iA和1 iA是可乘的,i=1,2,…,n-1。
考察这n个矩阵的连乘积nAAA ,2,1。
由于矩阵乘法具有结合律,故计算矩阵的连乘积可以有许多不同的计算次序。
这种计算次序可以用加括号的方式来确定。
若一个矩阵连乘积的计算次序完全确定,也就是说连乘积已完全加括号,则可依次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。
完全加括号的矩阵连乘可递归地定义为:(1)单个矩阵是完全加括号的;(2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘B和C的乘积并加括号,即A=(BC)。
矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。
若A 是一个p×q的矩阵,B是一个q×r的矩阵,那么C=A×B就是一个p×r矩阵。
它的计算是三重循环的,计算量是pqr。
如果加括号后矩阵的量是不同的,所以我们的问题就是要讨论如何给连乘的矩阵加括号才能使矩阵的计算量最少。
穷举搜索法:对于n个矩阵的连乘积,设有不同的计算次序P(n)。
由于可以先在第k个和第k+1个矩阵之间将原矩阵序列分为两个矩阵子序列,k=1,2,...,n-1;然后分别对这两个矩阵子序列完全加括号;最后对所得的结果加括号,得到原矩阵序列的一种完全加括号方式。
解递归方程可得,P(n)=C(n-1),而C(n)是一个指数增长的函数。
因此穷举搜索法不是一个有效的算法。
以下将用三种方法来解决矩阵连乘问题的最优加括号方式以及最优解。
(2)算法设计思想由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。
这种计算次序可以用加括号的方式来确定。
最近点对算法
最近点对算法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]内,查找可能的更近点对。
最近点对问题
算法分析与设计最近对问题最近对问题问题描述:在二维平面上的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 中。
最接近点对问题
一、最接近点对问题(一维)1、最接近点对问题(一维)最接近点对问题:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。
此时S中的n个点退化为x轴上的n个实数x1,x2,..,x n。
最接近点对即为这n 个实数中相差最小的2个实数。
2、分析将所给的平面上n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,·然后在每个子集中递归地求其最接近的点对。
S1和S2的最接近点对未必就是S的最接近点对,如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。
但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n2/4次计算和比较才能确定S的最接近点对。
因此,依此思路,合并步骤耗时为O(n2)。
整个算法所需计算时间T(n)应满足:T(n)=2T(n/2)+O(n2)它的解为T(n)=O(n2)3、伪代码随机Randomfloat Random(){float result=rand()%10000;return result*0.01;}返回最大、最小float Max OR Min(float s[],int p,int q)//返回s[]中的最大值{float s_max(s_min)=s[p];for(int i=p+1;i<=q;i++)if(s_max<s[i])s_max=s[i]; ORif(s_min>s[i])s_min=s[i];return s_max(s_min)}主要函数Cpair Cpair1(float s[],int n){Cpair out_p_d={99999,0,0};if(n<2) return out_p_d;float m1=Max(s,0,n-1),m2=Min(s,0,n-1);float m=(m1+m2)/2;//找出点集中的中位数int j=0,k=0;//将点集中的各元素按与m的大小关系分组float s1[M],s2[M];for(int i=0;i<n;i++){if(s[i]<=m) {s1[j]=s[i];j++;}else {s2[k]=s[i];k++;}}Cpair d1=Cpair1(s1,j),d2=Cpair1(s2,k);//递归float p=Max(s1,0,j-1),q=Min(s2,0,k-1);//返回s[]中的具有最近距离的点对及其距离if(d1.d<d2.d){if((q-p)<d1.d){out_p_d.d=(q-p);out_p_d.d1=q;out_p_d.d2=p;return out_p_d;}else return d1;}else{if((q-p)<d2.d){out_p_d.d=(q-p);out_p_d.d1=q;out_p_d.d2=p;return out_p_d;}else return d2;}}4、程序实现#include<time.h>#include <iostream>using namespace std;const int M=50;struct Cpair{float d;float d1,d2;};float Random();int input(float s[],int number_used);float Max(float s[],int p,int q);float Min(float s[],int p,int q);Cpair Cpair1(float s[],int n);void main(){srand((unsigned)time(NULL));int number_used,m;float s[M];Cpair d;m=input(s,number_used);d=Cpair1(s,m);cout<<endl<<"the closest pair is ("<<d.d1<<","<<d.d2<<")";cout<<endl<<"the min distance is "<<d.d<<endl;}float Random(){float result=rand()%10000;return result*0.01;}int input(float s[],int number_used){cout<<"input the number ";cin>>number_used;cout<<"the random number are ";for(int i=1;i<=number_used;i++){s[i]=Random();cout<<s[i]<<" ";}return number_used;}float Max(float s[],int p,int q)//返回s[]中的最大值{float s_max=s[p];for(int i=p+1;i<=q;i++)if(s_max<s[i])s_max=s[i];return s_max;}float Min(float s[],int p,int q)//返回s[]中的最小值{float s_min=s[p];for(int i=p+1;i<=q;i++)if(s_min>s[i])s_min=s[i];return s_min;}//返回s[]中的具有最近距离的点对及其距离Cpair Cpair1(float s[],int n){Cpair out_p_d={99999,0,0};if(n<2) return out_p_d;float m1=Max(s,0,n-1),m2=Min(s,0,n-1);float m=(m1+m2)/2;//找出点集中的中位数int j=0,k=0;//将点集中的各元素按与m的大小关系分组float s1[M],s2[M];for(int i=0;i<n;i++){if(s[i]<=m) {s1[j]=s[i];j++;}else {s2[k]=s[i];k++;}}Cpair d1=Cpair1(s1,j),d2=Cpair1(s2,k);//递归float p=Max(s1,0,j-1),q=Min(s2,0,k-1);//返回s[]中的具有最近距离的点对及其距离if(d1.d<d2.d){if((q-p)<d1.d){out_p_d.d=(q-p);out_p_d.d1=q;out_p_d.d2=p;return out_p_d;}else return d1;}{if((q-p)<d2.d){out_p_d.d=(q-p);out_p_d.d1=q;out_p_d.d2=p;return out_p_d;}else return d2;}}运行情况:二、最接近点对问题(二维)1、最接近点对问题(二维)二维时S中的点为平面上的点,它们都有2个坐标值x和y。
中科院陈玉福算法课件ch3ppt
MaxMin复杂性分析
• T(n)来表示MaxMin所用的元素比较数,则上述递归算法导出 一个递归关系式
n =1 ⎧0 ⎪ T (n) = ⎨1 n=2 ⎪ T( n/2 ) +T( n/2 ) + 2 n > 2 ⎤ ⎣ ⎦ ⎩ ⎡
• 当n是2的方幂时,设 n = 2 k ,有
•
• • •
T (n) = 2T (n / 2) + 2 = 2(2T (n / 4) + 2) + 2 L = 2k −1T (2) + = 3n / 2 − 2
以比较为基础的排序时间下界
每两个元素A[i]和A[j]的比较只 有两种可能: A[i]<A[j]或A[j]<A[i], 形成二叉树。当A[i]<A[j]时进入 左分支,当A[i]>A[j] 进入右分 支。各个叶结点表示算法终止。 从根到叶结点的每一条路径与一 种唯一的排列相对应。由于n个 不同元素的不同排列共有n!个 因此比较树有n!个外部结点 。 比较树中最长路径的长度(其是 比较树的高)即是算法在最坏情 况下所做的比较次数。要求出所 有以比较为基础的排序算法在最 坏情况下的时间下界,只需求出 这些算法所对应的比较树的高度 的最小值。
k: 0, 1, 2, 3, 4, 5, 6, 7, 8 LINK : 2, 8, 5, 4, 7, 3, 0, 1, 6
使用链接表的归并排序程序
proc MergeSortL(low, high, p) // Link是全程数组A[low..high] //的下标表, p指示这个表的开始处。利用Link将A按非降 //顺序排列。 global A[low..high]; Link[low..high]; if high-low+1<16 then //设定子问题的最小规模Small InSort(A,Link, low,high,p); else mid:=⎣(low+high)/2⎦; MergeSortL(low,mid,q); //返回q表 MergeSortL(mid+1,high,r); //返回r表 MergeL(q,r,p); 将表q和r合并成表p end{if} end{MergeSortL}
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
double spair (S ) { n =| S | ; //| S | 表示S中点的个数3 / if ( n < 2) return ∞; 1. m = S中各点y坐标的中位数; 利用平面P: y = m 划分构造子集S1 和S2 ; S1 = { p ∈ S | y ( p) < = m } , S2 = { p ∈ S| y ( p) > m } 2. d1 = spair (S1 ) ; d2 = spair (S2 ) ; 3. dm = min ( d1 , d2 ) ; 4. 设P1 是S1 中距垂直分割面P的距离在dm之内的所有点组成的集合; P2 是S2 中距垂直分割面的距离在dm 之内的所有点组成的集合; 将P1 和P2 中点依其依次按照其x坐标值和z坐标值排序; 并设X1、X2 是P1、P2 依据x坐标值排好序的点列; Z1、Z2 是X1、X2 再 依据z坐标值排好序的点列; 5. 通过扫描Z1 以及对于Z1 中每个点检查Z2中相继的最多24个点完成合并; 当Z1 中的扫描指针沿着某一个方向移动时,Z2 中的扫描指针可2dm×2dm 的方形区间内移动; 设d l是按这种扫描方式找到的点对间的最小距离; 6. d = min ( dm , d l) ; re turn d; }
( x(u ) x(v)) 2 ( y (u ) y (v)) 2 ( z (u ) z (v)) 2 (d / 2) 2 (d / 2) 2 (2d / 3) 2
17 2 d 18
distance(u,v)<d。这与d的意义相矛盾。
如何确定要检查哪24个点?
为了确切地知道对于P1 中每个点p最多检查P2 中的哪24个点,我们 可以将点p和P2 中所有S2的点投影到平面P: y = m上. 由于能与p点 一起构成最接近点对候选者的S2 中点一定在长方体R中,所以它们 在平面P上的投影点与点p在P上投影点的距离小于d. 由上面的分析 可知, 这种投影点最多只有24个. 因此,若将P1 和P2 中所有S的点依 次按其x坐标和z坐标排好序,则对P1 中任意点p而言,对已经按照x坐 标和z坐标排好序的点列作一次线性扫描,就可以找出所有最接近点 对的候选者. 设点q ( x, y, z) 为P2 中可以与P1 中的一点p ( x0 , y0 , z0 ) 构成候选点对的排好序的24个点中的一点,则满足x ∈ ( x0 - d, x0 + d) , z ∈ ( z0 - d, z0 +d) ,即投影点在以p的投影点为中心的2d ×2d的正方形区域中的点是我们要考察的候选点. 这就意味着我们 可以在O ( n) 时间内完成分治法的合并步骤.
选取一垂平面l:y=m来作为分割平面。其中m为S中各 点y坐标的中位数。由此将S分割为S1和S2。 递归地在S1和S2上找出其最小距离d1和d2,并设 d=min{d1,d2},S中的最接近点对或者是d,或者是某个 {p,q},其中p∈S1且q∈S2。
第一步筛选:如果最近点对由S1中的p3和
25 2 ( x(u ) x(v)) ( y (u ) y (v)) (d / 2) (2d / 3) d 36
2 2 2 2
distance(u,v)<d。这与d的意义相矛盾。
如何确定要检查哪6个点
P2中与点p最接近这6个候选点的纵坐标与p 的纵坐标相差不超过d. 因此,若将P1和P2中所有S中点按其y坐标 排好序,则对P1中所有点,对排好序的点列 作一次扫描,就可以找出所有最接近点对的候 选者。对P1中每一点最多只要检查P2中排好 序的相继6个点。
double cpair2(S)
复杂度分析
①、⑤用了O(n)时间; ②用了2T(n/2)时间 ③、⑥用了常数时间 ④在预排序的情况下用时O(n)
n4 O(1) T ( n) 2T (n / 2) O(n) n 4 T n On log n
分治法解决三维空间最接近点问题
在分治法的合并步骤中最多只需要检查6×n/2=3n 个候选点对!
R中最多只有6个S中的点 证明:将矩形R的长为2d的边3 * 鸽舍原理(也称抽屉原理) 等分,将它的长为 d的边2等分 把n+1个球,放入n个抽屉,则一定有一个抽屉内至少有2个球 ,由此导出 6个(d/2)×(2d/3)的 。 矩形。 若矩形R中有多于6个S中的 点,则由鸽舍原理易知至少有 一个(d/2)×(2d/3)的小矩形中 有2个以上S中的点。 设u,v是位于同一小矩形中 的2个点,则
S2中的q3组成,则p3和q3一定在划分平面 L的距离d内。
第二步筛选:考虑P1中任意一点p,它若与
P2中的点q构成最接近点对的候选者,则必 有distance(p,q)<d。满足这个条件的P2 中的点定落在一个d×2d×2d的长方体R中
重要观察结论:P2中任何2个S中的点的距离 都不小于d。由此可以推出长方体R中最多只有 24个S中的点。
S2中的q3组成,则p3和q3一定在划分线L 的距离d内。
第二步筛选:考虑P1中任意一点p,它若与
P2中的点q构成最接近点对的候选者,则必 有distance(p,q)<d。满足这个条件的P2 中的点一定落在一个d×2d的矩形R中
R中的点具有稀疏性
P2中任何2个S中的点的距离都不小于d。由 此可以推出矩形R中最多只有6个S中的点。
分治法解决二维空间ቤተ መጻሕፍቲ ባይዱ接近点问题
选取一垂直线l:x=m来作为分割直线。其中m为S中各 点x坐标的中位数。由此将S分割为S1和S2。 递归地在S1和S2上找出其最小距离d1和d2,并设 d=min{d1,d2},S中的最接近点对或者是d,或者是某个 {p,q},其中p∈S1且q∈S2。
第一步筛选:如果最近点对由S1中的p3和
4、设P1是S1中距垂直分割线l的距离在dm之 内的所有点组成的集合; { P2是S2中距分割线l的距离在dm之内所有 n=|S|; 点组成的集合; O(n) 将 P1 和 P2 中点依其 y 坐标值排序; if (n < 2) return ; 并设X和Y是相应的已排好序的点列; 1、m=S中各点x间坐标的中位数; 5、通过扫描X以及对于X中每个点检查Y中与 构造S1和S2; 其距离在dm之内的所有点(最多6个)可以完成 O(n) 合并; O(n) //S1={p∈S|x(p)<=m}, 当X中的扫描指针逐次向上移动时,Y中的 S2={p∈S|x(p)>m} 扫描指针可在宽为2dm的区间内移动; 2、d1=cpair2(S1); 设dl是按这种扫描方式找到的点对间的最 2T(n/2 小距离; d2=cpair2(S2); ) 6、d=min(dm,dl); 常数时间 3、dm=min(d1,d2); return d; 常数时间 }
在分治法的合并步骤中最多只需要检24×n/2=12n 个候选点对。
R中最多只有24个S中的点
由d的意义可知, P2 中任何2个S中的 点的距离都不小于d. 由此可以推出长 方体R中最多只有24个S 中的点. 事实 上,我们可以将长方体C的长为2d的两 条边分别3等分和4等分,将它的长为d 的边2等分, 由此导出24个大小相等的( d /2) ×( d /2) ×(2d /3) 的小长方体. 如图3所示:若长方体C中有多于24个S 中的点,则由鸽舍原理易知至少有一个( d /2) ×( d /2) ×(2d /3) 的小长方体中 有2个以上S中的点. 设u, v是这样2个 点,它们位于同一小长方体中, distance ( u, v)
n4 O(1) T ( n) 2T (n / 2) O(n) n 4 T n On log n
Thank You!
三维空间最接近点问题
问题:给定平面上n个点,找其中的一对点,使得 在n个点所组成的所有点对中,该点对间的距离最 小。 说明:
严格来讲,最接近点对可能多于一对,为简便起见,我
们只找其中的一对作为问题的解。 一个简单的做法是将每一个点与其他n-1个点的距离算出, 找出最小距离的点对即可。该方法的时间复杂性是 T(n)=n(n-1)/2+n=O(n2),效率较低。 已经证明,该算法的计算时间下界是Ω(nlogn)。