0007算法笔记分治法最接近点对问题.docx

上传人:b****1 文档编号:1172035 上传时间:2022-10-18 格式:DOCX 页数:15 大小:34.34KB
下载 相关 举报
0007算法笔记分治法最接近点对问题.docx_第1页
第1页 / 共15页
0007算法笔记分治法最接近点对问题.docx_第2页
第2页 / 共15页
0007算法笔记分治法最接近点对问题.docx_第3页
第3页 / 共15页
0007算法笔记分治法最接近点对问题.docx_第4页
第4页 / 共15页
0007算法笔记分治法最接近点对问题.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

0007算法笔记分治法最接近点对问题.docx

《0007算法笔记分治法最接近点对问题.docx》由会员分享,可在线阅读,更多相关《0007算法笔记分治法最接近点对问题.docx(15页珍藏版)》请在冰豆网上搜索。

0007算法笔记分治法最接近点对问题.docx

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。

最接近点对即为这n个实数中相差最小的2个实数。

我们显然可以先将x1,x2,..,xn排好序,然后,用一次线性扫描就可以找出最接近点对。

这种方法主要计算时间花在排序上,在排序算法已经证明,时间复杂度为O(nlogn)。

然而这种方法无法直接推广到二维的情形。

因此,对这种一维的简单情形,我们还是尝试用分治法来求解,并希望能推广到二维的情形。

假设我们用x轴上某个点m将S划分为2个子集S1和S2,使得S1={x∈S|x≤m};S2={x∈S|x>m}。

这样一来,对于所有p∈S1和q∈S2有p

递归地在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|

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

同理,(m,m+d]中也至多包含S中的一个点。

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

同理,如果(m,m+d]中有S中的点,则此点就是S2中最小点。

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

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

也就是说,按这种分治策略,合并步可在O(n)时间内完成。

这样是否就可以得到一个有效的算法了呢?

还有一个问题需要认真考虑,即分割点m的选取,及S1和S2的划分。

选取分割点m的一个基本要求是由此导出集合S的一个线性分割,即S=S1∪S2 ,S1∩S2=Φ,且S1={x|x≤m};S2={x|x>m}。

容易看出,如果选取m=[max(S)+min(S)]/2,可以满足线性分割的要求。

选取分割点后,再用O(n)时间即可将S划分成S1={x∈S|x≤m}和S2={x∈S|x>m}。

然而,这样选取分割点m,有可能造成划分出的子集S1和S2的不平衡。

例如在最坏情况下,|S1|=1,|S2|=n-1,由此产生的分治法在最坏情况下所需的计算时间T(n)应满足递归方程:

  T(n)=T(n-1)+O(n)

   它的解是T(n)=O(n^2)。

这种效率降低的现象可以通过分治法中“平衡子问题”的方法加以解决。

即通过适当选择分割点m,使S1和S2中有大致相等个数的点。

自然地,我们会想到用S的n个点的坐标的中位数来作分割点。

在选择算法中介绍的选取中位数的线性时间算法使我们可以在O(n)时间内确定一个平衡的分割点m。

     本程序确定平衡点采用m=[max(S)+min(S)]/2方法。

如果需要利用中位数作分割点,看结合笔者博文《0005算法笔记——线性时间选择》改写。

   一维最接近临近点对问题程序清单如下:

[cpp] viewplain copy

1.//2d10-1 一维最邻近点对问题  

2.#include "stdafx.h"  

3.#include   

4.#include    

5.using namespace std;   

6.const int L=100;  

7.//点对结构体  

8.struct Pair  

9.{  

10.    float d;//点对距离  

11.    float d1,d2;//点对坐标  

12.};  

13.float Random();  

14.int input(float s[]);//构造S  

15.float Max(float s[],int p,int q);  

16.float Min(float s[],int p,int q);  

17.template   

18.void Swap(Type &x,Type &y);  

19.template   

20.int Partition(Type s[],Type x,int l,int r);  

21.Pair Cpair(float s[],int l,int r);  

22.int main()  

23.{  

24.    srand((unsigned)time(NULL));  

25.    int m;  

26.    float s[L];  

27.    Pair d;  

28.    m=input(s);  

29.    d=Cpair(s,0,m-1);  

30.    cout<

 (d1:

"<

"<

31.    cout<

 "<

32.    return 0;  

33.}  

34.float Random()  

35.{  

36.    float result=rand()%10000;  

37.     return result*0.01;  

38.}  

39.int input(float s[])  

40.{  

41.    int length;  

42.    cout<<"输入点的数目:

 ";  

43.    cin>>length;  

44.    cout<<"点集在X轴上坐标为:

";  

45.    for(int i=0;i

46.    {  

47.        s[i]=Random();  

48.        cout<

49.    }  

50.    return length;  

51.}  

52.float Max(float s[],int l,int r)//返回s[]中的最大值  

53.{  

54.    float s_max=s[l];  

55.    for(int i=l+1;i<=r;i++)  

56.        if(s_max

57.            s_max=s[i];  

58.    return s_max;  

59.}  

60.float Min(float s[],int l,int r)//返回s[]中的最小值  

61.{  

62.    float s_min=s[l];  

63.    for(int i=l+1;i<=r;i++)   

64.        if(s_min>s[i])  

65.            s_min=s[i];  

66.    return s_min;  

67.}  

68.template   

69.void Swap(Type &x,Type &y)  

70.{  

71.    Type temp = x;  

72.    x = y;  

73.    y = temp;  

74.}  

75.template   

76.int Partition(Type s[],Type x,int l,int r)  

77.{  

78.    int i = l - 1,j = r + 1;  

79.    while(true)  

80.    {  

81.        while(s[++i]

82.        while(s[--j]>x);  

83.        if(i>=j)  

84.        {  

85.            break;  

86.        }  

87.        Swap(s[i],s[j]);  

88.    }  

89.    return j;  

90.}  

91.//返回s[]中的具有最近距离的点对及其距离  

92.Pair Cpair(float s[],int l,int r)  

93.{  

94.    Pair min_d={99999,0,0};//最短距离  

95.    if(r-l<1) return min_d;  

96.    float m1=Max(s,l,r),m2=Min(s,l,r);  

97.    float m=(m1+m2)/2;//找出点集中的中位数  

98.    //将点集中的各元素按与m的大小关系分组  

99.    int j = Partition(s,m,l,r);  

100.    Pair d1=Cpair(s,l,j),d2=Cpair(s,j+1,r);//递归  

101.    float p=Max(s,l,j),q=Min(s,j+1,r);  

102.    //返回s[]中的具有最近距离的点对及其距离  

103.    if(d1.d

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 交通运输

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1