最接近点对问题

合集下载

分治法解决问题的步骤

分治法解决问题的步骤

分治法解决问题的步骤一、基础概念类题目(1 - 5题)题目1:简述分治法解决问题的基本步骤。

解析:分治法解决问题主要有三个步骤:1. 分解(Divide):将原问题分解为若干个规模较小、相互独立且与原问题形式相同的子问题。

例如,对于排序问题,可将一个大的数组分成两个较小的子数组。

2. 求解(Conquer):递归地求解这些子问题。

如果子问题规模足够小,则直接求解(通常是一些简单的基础情况)。

对于小到只有一个元素的子数组,它本身就是有序的。

3. 合并(Combine):将各个子问题的解合并为原问题的解。

在排序中,将两个已排序的子数组合并成一个大的有序数组。

题目2:在分治法中,分解原问题时需要遵循哪些原则?解析:1. 子问题规模更小:分解后的子问题规模要比原问题小,这样才能逐步简化问题。

例如在归并排序中,不断将数组对半分,子数组的长度不断减小。

2. 子问题相互独立:子问题之间应该尽量没有相互依赖关系。

以矩阵乘法的分治算法为例,划分后的子矩阵乘法之间相互独立进行计算。

3. 子问题与原问题形式相同:方便递归求解。

如二分查找中,每次查找的子区间仍然是一个有序区间,和原始的有序区间查找问题形式相同。

题目3:分治法中的“求解”步骤,如果子问题规模小到什么程度可以直接求解?解析:当子问题规模小到可以用简单的、直接的方法(如常量时间或线性时间复杂度的方法)解决时,就可以直接求解。

例如,在求数组中的最大最小值问题中,当子数组只有一个元素时,这个元素既是最大值也是最小值,可以直接得出结果。

题目4:分治法的“合并”步骤有什么重要性?解析:1. 构建完整解:它将各个子问题的解组合起来形成原问题的解。

例如在归并排序中,单独的两个子数组排序好后,只有通过合并操作才能得到整个数组的有序排列。

2. 保证算法正确性:如果合并步骤不正确,即使子问题求解正确,也无法得到原问题的正确答案。

例如在分治算法计算斐波那契数列时,合并不同子问题的结果来得到正确的斐波那契数是很关键的。

蛮力法和分治法的性能比较

蛮力法和分治法的性能比较

蛮力法与分治法求解最近对问题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章

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分治法(最近点对)

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
黑盒划分典型问题—逆序对问题

最近点对算法

最近点对算法

最近点对算法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]内,查找可能的更近点对。

中科院陈玉福算法课件ch3ppt

中科院陈玉福算法课件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. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、最接近点对问题(一维)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。

给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。

2、分析设对于n个点的平面点集S,算法耗时T(n)。

算法的求中位数和合并用了O(n)时间,求最小距离用了常数时间,递归用了2T(n/2)时间。

我们采用设计算法时常用的预排序技术,即在使用分治法之前,预先将S中n个点依其y坐标值排好序,设排好序的点列为P*。

在执行的两遍扫描合在一起只要用O(n)时间。

这样一来,经过预排序处理后的算法CPAIR2所需的计算时间T(n)满足递归方程:显而易见T(n)=O(n log n),预排序所需的计算时间为O(n1og n)。

因此,整个算法所需的计算时间为O(n log n)。

用类PointX和PointY表示依x坐标和y坐标排好序的点class PointX {public:int operator<=(PointX a)const{ return (x<=a.x); }int ID; //点编号float x,y; //点坐标};class PointY {public:int operator<=(PointY a)const{ return(y<=a.y); }求距离Dis=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)假设我们用x轴上某个点m将S划分为2个子集S1和S2 ,基于平衡子问题的思想,用S中各点坐标的中位数来作分割点。

递归地在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设d=min{|p1-p2|,|q1-q2|},S中的最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。

如果S的最接近点对是{p3,q3},即|p3-q3|小于d,则p3和q3两者与m的距离不超过d,即p3∈(m-d,m],q3∈(m,m+d]。

由于在S1中,每个长度为d的半闭区间至多包含一个点(否则必有两点距离小于d),并且m是S1和S2的分割点,因此(m-d,m]中至多包含S中的一个点。

由图可以看出,如果(m-d,m]中有S中的点,则此点就是S1中最大点。

因此,我们用线性时间就能找到区间(m-d,m]和(m,m+d]中所有点,即p3和q3。

从而我们用线性时间就可以将S1的解和S2的解合并成为S的解。

选取一垂直线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中的点。

因此,在分治法的合并步骤中最多只需要检查6×n/2=3n个候选者。

为了确切地知道要检查哪6个点,可以将p和P2中所有S2的点投影到垂直线l 上。

相关文档
最新文档