基于递归法的最接近点对问题

合集下载

最接近点对问题

最接近点对问题

一、最接近点对问题(一维)一、最接近点对问题(一维)最接近点对问题:给定平面上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*;}返回最大、最小float Max OR Min(float s[],int p,intq)序实现#include<>#include<iostream>#include<cmath>using namespace std;const int M=50;D=i;X[i].x=Random();X[i].y=Random();c out<<"("<<X[i].x<<","<<X[i].y<<") ";}PointX a;PointX b;float d;Cpair2(X,number_used,a,b,d);cout<<endl;cout<<"the closest pair is ("<<<<","<<<<")和("<<<<","<<<<") "<<endl;cout<<"the min distance is "<<d<<endl;return 0;}float Random(){float result=rand()%10000;return result*;}=i;Y[i].x=X[i].x;Y[i].y=X[i].y;}PointY*tmpy=new PointY[n];MergeSort(Y,tmpy,0,n-1);PointY*Z=new PointY[n];closest(X,Y,Z,0,n-1,a,b,d);delete []Y;delete []Z;return true;}void closest(PointX X[],PointY Y[],PointY Z[], int l, int r,PointX& a,PointX& b,float& d){i f(r-l==1){>m) Z[g++]=Y[i];else Z[f++]=Y[i]; closest(X,Z,Y,l,m,a,b,d);float dr;PointX ar,br;closest(X,Z,Y,m+1,r,ar,br,dr);if(dr<d){a=ar;b=br;d=dr;}Merge(Z,Y,l,m,r);-Y[t].x)<d){Z[k++]=Y[t];}-Z[s].y<d;j++){float dp=dis(Z[s],Z[j]);if(dp<d){d=dp;a=X[Z[i].p];b=X[Z[j].p];} } } }template <typename Type>void Merge(Type c[],Type d[], int l, int m, int r){i nt i=l,j=m+1,k=l;w hile((i<=m)&&(j<=r))if(c[i]<=c[j])d[k++]=c[i++];elsed[k++]=c[j++];if(i>m)for(int q=j;q<=r;q++)d[k++]=c[q];elsefor(int q=i;q<=m;q++)d[k++]=c[q];}template <typename Type>void MergeSort(Type a[], Type b[],int left, int right){ // a[]为待排序的数组,left,right为a数组的下标,b[]为临时存放排好序的临时数组i f(left<right){int i=(left+right)/2;//取中点MergeSort(a,b,left,i);MergeSort(a,b,i+1,right);Merge(a,b,left,i,right);//归并到数组bCopy(a,b,left,right);//复制回数组a }}template <typename Type>void Copy(Type a[],Type b[], int right,int left) {for(int i=right;i<=left;i++)a[i]=b[i];}运行情况:。

最近点对问题

最近点对问题

最近点对问题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中的点。

基于递归法的最接近点对问题

基于递归法的最接近点对问题

基于递归法的最接近点对问题目录1、问题综述 (2)2、用递归法解决 (2)2.1 一维情形下的分析 (2)2.2 二维情形下的分析 (4)2.3 算法优化 (6)2.4 算法实现 (6)3、结论 (9)基于递归法的最接近点对问题摘要:在计算机应用中,常用诸如点、圆等简单的几何对象表现现实世界中的实体。

在涉及几何对象的问题中,常需要了解其邻域中其他几何对象的信息。

例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来处理,则具有最大碰撞危险的两架飞机就是这个空间中最近的一点。

这类问题是计算机几何学中研究的基本问题之一。

本文就运用递归法对一维和二维的情况加以讨论。

关键词:最接近点对递归法1、问题综述最接近点对问题的提法是:给定平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。

实际情况下,最接近点对可能多于一对,为简单起见,我们只找其中的一对作为问题的解。

有一个最直观的方法就是将每一点与其他n-1个点的距离算出,找出达到最小距离的两点即可。

然而,这样做效率太低,我们想到用递归法来解决这个问题。

2、用递归法解决将所给的平面上n个点的集合S分成两个子集S1和S2 ,每个子集中约有n/2个点。

然后在每个子集中递归地求其最接近的点对。

在这里,一个关键的问题是如何实现递归法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。

如果组成S 的最接近点对的两个点都在S1中或都在S2中,则问题很明显就可以找到答案。

可是还存在另外一种可能,就是这两给点分别在S1和S2 中的时候。

下面主要讨论这种情况。

2.1 一维情形下的分析为使问题易于理解和分析,我们先来考虑一维的情形。

此时,S中的n各点退化为x 轴上的n个实数x1,x2,x3…x n。

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

我们尝试用递归法来求解,并希望推广到二维的情形。

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

最近对问题_递归与分治算法

最近对问题_递归与分治算法

实验 1 递归与分治算法一,实验目的和要求(1)进一步掌握递归算法的设计思想以及递归程序的调试技术;(2)理解这样一个观点:分治与递归经常同时应用在算法设计之中。

(3)分别用蛮力法和分治法求解最近对问题;(4)分析算法的时间性能,设计实验程序验证分析结论。

二,实验容设p仁(x1, y1), p2=(x2, y2), …,pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。

三,实验环境Turbo C 或VC++四,实验学时2 学时,必做实验五,数据结构与算法#include<iostream.h>#include<cmath>#define TRUE 1#define FALSE 0typedef struct Node{double x;double y;}Node; // 坐标typedef struct List{Node* data; // 点int count; // 点的个数}List;typedef struct CloseNode{Node a;Node b; // 计算距离的两个点double space; // 距离平方}CloseNode;int n; // 点的数目// 输入各点到List 中void create(List &L){cout<<" 请输入平面上点的数目:\n";cin>>n;L.count=n;L.data = new Node[L.count]; // 动态空间分配cout<<" 输入各点坐标:x_y):"<<endl; for(int i=0;i<L.count;++i)cin>>L.data[i].x>>L.data[i].y;}// 求距离的平方double square(Node a,Node b){return ((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y));}// 蛮力法void BruteForce(const List &L,CloseNode &cnode,int begin,int end) {for(int i=begin;i<=end;++i){for(int j=i+1;j<=end;++j){double space=square(L.data[i],L.data[j]); if(space<cnode.space){ode.a=L.data[i];ode.b=L.data[j]; ode.space=space;}}}}// 冒泡排序void BubbleSort(Node r[],int length){int change,n;n=length;change=TRUE;double b,c;for(int i=0;i<n-1&&change;++i){ change=FALSE; for(int j=0;j<n-i-1;++j) {if(r[j].x>r[j+1].x){b=r[j].x;c=r[j].y; r[j].x=r[j+1].x;r[j].y=r[j+1].y; r[j+1].x=b;r[j+1].y=c;change=TRUE;}}}}判断纵坐标是// 分治法中先将坐标按 X 轴从小到大的顺序排列void paixu(List L){BubbleSort(L.data,L.count); // 调用冒泡排序}// 左右各距中线 d 的区域的最近对算法void middle(const List & L,CloseNode &cnode,int mid,double midX){int i,j; // 分别表示中线左边,右边的点double d=sqrt(cnode.space);i=mid;while(i>=0&&L.data[i].x>=(midX-d)) // 在左边的 d 区域{j=mid;while(L.data[++j].x<=(midX+d)&&j<=L.count) // 在右边的 d 区域 {if(L.data[j].y<(L.data[i].y-d)||L.data[j].y>(L.data[i].y+d)) // 否在左边某固定点的 2d 区域continue;double space = square(L.data[i],L.data[j]);if(cnode.space>space) // 在满足条件的区域依次判断{ode.a=L.data[i];ode.b=L.data[j];ode.space=space;}继续在左半边用分治法求最近对 继续在右半边用分治法求最近对 判断左右各距中线 d 的区域,是否有最--i;}}// 分治法求最近对void DivideConquer(const List &L,CloseNode &closenode,int begin,int end) {if(begin!=end){int mid = (begin+end)/2; // 排列后的中间的那个点double midX = L.data[mid].x;DivideConquer(L,closenode,begin,mid); //DivideConquer(L,closenode,mid+1,end); //middle(L,closenode,mid,midX); // 近对}} void main(){// 初始化List list;CloseNode closenode;closenode.space = 10000; // 最近点的距离create(list); // 输入各点到 NList 中cout<<" 各点坐标为 :"<<endl;for(int i=0;i<list.count;++i)cout<<"X="<<list.data[i].x<<" Y="<<list.data[i].y<<"\n";BruteForce(list,closenode,0,list.count-1);cout<<" 用蛮力法求最近对 :"<<endl;cout<<" 最 近 对 为 点 ("<<closenode.a.x<<","<<closenode.a.y<<") 和 点("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<" 最 近 距 离 为 : "<<sqrt(closenode.space)<<endl; cout<<endl<<endl;cout<<" 用分治法求最近对 :"<<endl;paixu(list);cout<<" 经过排序后的各点 :"<<endl;for(int j=0;j<list.count;++j)cout<<"X="<<list.data[j].x<<" Y="<<list.data[j].y<<"\n";DivideConquer(list,closenode,0,list.count-1);cout<<" 最 近 对 为 点 ("<<closenode.a.x<<","<<closenode.a.y<<") 和 点("<<closenode.b.x<<","<<closenode.b.y<<")\n"<<" 最 近 距 离 为 : "<<sqrt(closenode.space)<<endl;排列后的中间的那个点 继续在左半边用分治法求最近对继续在右半边用分治法求最近对六,核心源代码// 左右各距中线 d 的区域的最近对算法void middle(const List & L,CloseNode &cnode,int mid,double midX){int i,j; // 分别表示中线左边,右边的点double d=sqrt(cnode.space);i=mid; while(i>=0&&L.data[i].x>=(midX-d)) // 在左边的 d 区域{j=mid; while(L.data[++j].x<=(midX+d)&&j<=L.count) // 在右边的 d 区域{if(L.data[j].y<(L.data[i].y-d)||L.data[j].y>(L.data[i].y+d)) // 判断纵坐标是 否在左边某固定点的 2d 区域 continue;double space = square(L.data[i],L.data[j]);if(cnode.space>space) // 在满足条件的区域依次判断{ode.a=L.data[i];ode.b=L.data[j];ode.space=space;}}--i;} }// 分治法求最近对void DivideConquer(const List &L,CloseNode &closenode,int begin,int end){if(begin!=end){ int mid = (begin+end)/2; // double midX = L.data[mid].x; DivideConquer(L,closenode,begin,mid); //DivideConquer(L,closenode,mid+1,end); // middle(L,closenode,mid,midX); // 近对七,实验结果八,实验体会通过这次实验,我深刻了解到分治法的实用性,有效性。

最近点对算法

最近点对算法

最近点对算法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算法笔记——【分治法】最接近点对问题

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个点中,如何快速的找出最近的⼀对点,就是最近点对问题。

⼀种简单的想法是暴⼒枚举每两个点,记录最⼩距离,显然,时间复杂度为O(n^2)。

在这⾥介绍⼀种时间复杂度为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},如下图所⽰。

如果最接近点对是{q3,p3},即|p3-q3|<d,则p3和q3两者与m的距离都不超过d,且在区间(m-d,d]和(d,m+d]各有且仅有⼀个点。

这样,就可以在线性时间内实现合并。

此时,⼀维情形下的最近点对时间复杂度为O(nlogn)。

在⼆维情形下,类似的,利⽤分治法,但是难点在于如何实现线性的合并?由上图可见,形成的宽为2d的带状区间,最多可能有n个点,合并时间最坏情况下为n^2,。

但是,P1和P2中的点具有以下稀疏的性质,对于P1中的任意⼀点,P2中的点必定落在⼀个d X 2d的矩形中,且最多只需检查六个点(鸽巢原理)。

用分治算法解平面最接近点对问题

用分治算法解平面最接近点对问题

一. 用分治算法解平面最接近点对问题1.题目关于最接近点对问题:给定平面上n个点,找出其中一对点,使得在n个点所构成的所有点对中,该点对的距离最小。

2.程序详细介绍(各模块的功能等)本程序主要包括两个类:类Point和类Ppoint.其中类Point为处理一些的基本数据传递等.类Ppoint为该程序的主要实现模块,该类中有输入点对的函数shuru,对所输入的点对按X轴排序的函数sort,求各点对的距离的函数xiao等.假设S中的点为平面上的点,它们都有2个坐标值x和y。

为了将平面上点集S线性分割为大小大致相等的2个子集S1和S2,我们选取一垂直线l(方程:x=m)来作为分割直线。

其中m为S中各点x坐标的中位数。

由此将S分割为S1={p∈S|px≤m}和S2={p∈S|px>m}。

从而使S1和S2分别位于直线l的左侧和右侧,且S=S1∪S2 。

由于m是S中各点x坐标值的中位数,因此S1和S2中的点数大致相等。

递归地在S1和S2上解最接近点对问题,我们分别得到S1和S2中的最小距离δ1和δ2.此即为该程序的大致算法.3. 程序结构(流程图)该程序的流程图如下所示4. 调试与测试:调试方法,测试结果(包括输入数据和输出结果)的分析与讨论运行该程序时,屏幕上会出现一个界面,首先该界面会提示输入要处理的点对个数,输入点对个数后从键盘输入数字0即可显示出处理后的各个结果,会出现如下结果:5.程序代码(源程序)#include<iostream>#include<cmath>#include<fstream>using namespace std;int i,j,k,d,m,n;double p2,q,s,r,t;class Point //创建一个点类//{public:double x;double y;double getx(){return x;}double gety(){return y;}friend class Ppoint;};class Ppoint{int sum;double juli[10][10];double min[11]; //min[10]用来存放每组中最短的距离//double mini[11]; //mini[10]用来存放每组中距离最短的点对中的第一个点//double minj[11]; //minj[10]用来存放每组中距离最短的点对中的第二个点//Point p[100];Point p1;public:void shuru(){cout<<"请输入要处理的点的个数"<<endl;cin>>sum;for(i=0;i<sum;i++){cout<<"请输入点对"<<endl;cin>>p[i].x;cin>>p[i].y;cout<<p[i].x<<","<<p[i].y<<endl;}}void sort(){cout<<"以下是按x轴上由小到大排序后的点对"<<endl;for(i=0;i<sum-1;i++){for(j=i+1;j<sum;j++){if(p[i].x>p[j].x){p1=p[i];p[i]=p[j];p[j]=p1;}}}for(i=0;i<sum;i++){cout<<p[i].x<<","<<p[i].y<<endl;}}void xiao(){cout<<"以下是对每个模块中的点求距离"<<endl;for(k=0;k<sum/10;k++){cout<<"按任意键继续"<<endl;cin>>i;cout<<"以下是第"<<k<<"个模块中的距离"<<endl;for(i=1;i<10;i++){for(j=0;j<i;j++){r=abs(p[k*10+i].x-p[k*10+j].x);t=abs(p[k*10+i].y-p[k*10+j].y);juli[i][j]=sqrt(r*r+t*t);cout<<juli[i][j]<<"\t";}cout<<endl;}min[k]=juli[k][0],mini[k]=10*k+1,minj[k]=10*k;for(i=1;i<10;i++){cout<<"\n"<<"第"<<i<<"行以前的最小值为"<<min[k]<<endl;for(j=0;j<i;j++){if(juli[i][j]<min[k]){min[k]=juli[i][j];mini[k]=10*k+i;minj[k]=10*k+j;}}}cout<<"\n"<<"这是第"<<k<<"个模块中的结果"<<endl;cout<<"\n"<<"距离最小值为"<<min[k]<<endl;cout<<"\n"<<"距离最小值的第一个点为"<<mini[k]<<endl; //cout<<"距离最小值的第一个点为"<<mini[k]<<endl;//}if(sum%10!=0){k=sum/10;cout<<"输入0显示结果"<<endl;cin>>i;for(i=1;i<sum%10;i++){for(j=0;j<i;j++){m=abs(p[k*10+i].x-p[k*10+j].x);n=abs(p[k*10+i].y-p[k*10+j].y);juli[i][j]=sqrt(m*m+n*n);cout<<juli[i][j];cout<<"\t";}cout<<endl;}min[k]=juli[1][0],mini[k]=10*k+1,minj[k]=10*k;for(i=1;i<sum%10;i++){cout<<"\n"<<"第"<<i<<"行以前的最小值为"<<min[k]<<endl;for(j=0;j<i;j++){if(juli[i][j]<min[k]){min[k]=juli[i][j];mini[k]=10*k+i;minj[k]=10*k+j;}}}cout<<"\n"<<"这是第"<<k<<"个模块中的结果"<<endl;cout<<"\n"<<"距离最小值为"<<min[k]<<endl;cout<<"\n"<<"距离最小值的第一个点为"<<mini[k]<<endl; //cout<<"距离最小值的第一个点为"<<mini[k]<<endl;}}void realmin(){cout<<"\n"<<"几个模块中的最小值是:"<<min[10]<<endl;for(i=0,min[10]=min[0],mini[10]=mini[0],minj[10]=minj[0];i<=sum/10;i++){if(min[i]<min[10]){min[10]=min[i];mini[10]=mini[i];minj[10]=minj[i];}}}void bianjiemin(){cout<<"\n"<<" 包括边界的最小值是:"<<min[10]<<endl;for(i=0;i<sum/10;i++){for(k=9;k>=0;k--)if(p[(i+1)*10].x-p[i*10+k].x<min[10]){for(q=0;q<10;q++)if(p[(i+1)*10+m].x-p[(i+1)*10].x<min[10]){m=abs(p[i*10+k].x-p[(i+1)*10+m].x);n=abs(p[i*10+k].y-p[(i+1)*10+m].y);if(min[10]>sqrt(m*m+n*n)){min[10]=sqrt(m*m+n*n);mini[10]=i*10+k;minj[10]=(i+1)*10+q;}}elsebreak;}elsebreak;}}void shuchu(){i=mini[10];j=minj[10];p2= abs(p[i].x-p[j].x)*abs(p[i].x-p[j].x) ;q= abs(p[i].x-p[j].x)*abs(p[i].x-p[j].x) ;s=sqrt(p2+q);cout<<"\n"<<"最接近点对为"<<"p["<<i<<"]"<<"("<<p[i].x<<","<<p[i].y<<")"<<" "<<"p["<<j<<"]"<<"("<<p[j].x<<","<<p[j].y<<")"<<endl;cout<<"\n"<<"最短距离为"<<min[10];cout<<"\n"<<"最短距离为"<<s;}};int main(){Ppoint x;x.shuru();x.sort();x.xiao();x.realmin();x.bianjiemin();x.shuchu();return 0;}二.设计体会通过这次的课程设计,我对C++程序语言有了更进一步的认识。

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

基于递归法的最接近点对问题姓名:杨意学号:309040102009学院:数学信息学院专业:计算机辅助教育目录1、问题综述22、用递归法解决22.1 一维情形下的分析 22.2 二维情形下的分析 32.3 算法优化 62.4 算法实现 63、结论9基于递归法的最接近点对问题摘要:在计算机应用中,常用诸如点、圆等简单的几何对象表现现实世界中的实体。

在涉及几何对象的问题中,常需要了解其邻域中其他几何对象的信息。

例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来处理,则具有最大碰撞危险的两架飞机就是这个空间中最近的一点。

这类问题是计算机几何学中研究的基本问题之一。

本文就运用递归法对一维和二维的情况加以讨论。

关键词:最接近点对递归法问题综述最接近点对问题的提法是:给定平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。

实际情况下,最接近点对可能多于一对,为简单起见,我们只找其中的一对作为问题的解。

有一个最直观的方法就是将每一点与其他n-1个点的距离算出,找出达到最小距离的两点即可。

然而,这样做效率太低,我们想到用递归法来解决这个问题。

2、用递归法解决将所给的平面上n个点的集合S分成两个子集S1和S2 ,每个子集中约有n/2个点。

然后在每个子集中递归地求其最接近的点对。

在这里,一个关键的问题是如何实现递归法中的合并步骤,即由S1 和S2的最接近点对,如何求得原集合S中的最接近点对。

如果组成S的最接近点对的两个点都在S1中或都在S2中,则问题很明显就可以找到答案。

可是还存在另外一种可能,就是这两给点分别在S1和S2 中的时候。

下面主要讨论这种情况。

2.1 一维情形下的分析为使问题易于理解和分析,我们先来考虑一维的情形。

此时,S中的n各点退化为x轴上的n个实数x1,x2,x3…xn。

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

我们尝试用递归法来求解,并希望推广到二维的情形。

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

这样一来,对于所有p∈和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 。

如图2-1-1所示。

图2-1-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 的分割点,由图2-1-1可以看出,如果(m-d,m]中有S中点,则此点就是S1中最大点。

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

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

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

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

选取分割点m的一个基本要求是由此将S进行分割,使得S= S1∪S2 ,S1≠Φ,S2 ≠Φ,且S1∈{x|x ≤m },S2 ∈{x| x>m }。

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

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

例如在最坏情况下,| S1|=1,| S2 |=n-1,这样的计算效率与分割前相比提高幅度不明显。

这种现象可以通过递归法中“平衡子问题”的方法加以解决。

我们可以适当选择分割点m,使S1和S2 中有个数大致相等的点。

我们会想到用S中各点坐标的中位数来作为分割点。

由此,我们设计出一个求一维点集S的最接近点对的算法Cpair 1如下:---------------------------------------------------------------Bool Cpair 1(S,d){N=|S|;if(n<2){d=∞;return false;}m=S中各点坐标的中位数;//构造S1和S2 ;S1={x∈S | x≤m} ;S2 ={ x∈S | x>m };Cpair 1(S1,d1);Cpair 1(S2 ,d2);p=max(S1);q=min(S2 );d=min(d1,d2,q-p);return true}------------------------------------------------------------------2.2 二维情形下的分析以上一维算法可以推广到二维的情形。

设S中的点为平面上的点,它们都有两个坐标值x和y。

为了将平面上点集S线性分割为大小大致相等的两个子集S1和S2 ,我们选取一垂直线L:x=m来作为分割直线。

其中,m 为S中各点x坐标的中位数。

由此将S分割为S1={p∈S | x (p) ≤m }和S2 ={p∈S | x (p) >m }。

从而使S1和S2 分别位于直线L的左侧和右侧,且S=S1∪S2 。

由于m是S中各x 坐标的中位数,因此S1和S2 中得点数大致相等。

递归地在S1和S2 上解最接近点对问题,我们分别得到S1和S2 中的最小距离d1和d2。

现设d=min{d1,d2}。

若S的最接近点对(p,q)之间的距离小于d,则p和q必分属于S1和S2 。

不妨设p∈S1,q∈S2 。

那么p和q距直线L的距离均小于d。

因此,若我们用P1和P2分别表示直线L的左边和右边的宽为d的两个垂直长条区域,则p∈P1且q∈P2,如图2-2-1所示。

图2-2-1 距直线L的距离小于d的所有点在一维情形下,距分割点距离为d的两个区间(m-d,m]和(m,m+d]中最多各有S中一个点。

因而这两点成为唯一的未检查过的最接近点对候选者。

二维的情形则要复杂些。

此时,P1中所有点和P2中所有点构成的点对均为最接近点对的候选者。

在最坏的情况下有n2/4对这样的候选者。

考虑P1中任意一点p,它若与P2中的点q构成最接近点对的候选者,则必有distance(p,q) <d。

满足这个条件的P2中的点有多少个呢?容易看出这样的点一定落在一个d*2d的矩形R中,如图2-2-2所示。

图2-2-2 包含点q的d*2d矩形R由d的意义可知,P2中任何两个S中的点的距离都不小于d。

由此可以推出矩形R中最多只有6个S中的点。

下面我们来证明这个结论。

我们可以将矩形R的长为2d的边3等分,将它的长为d的边2等分,由此导出6个(d /2)*(2d/3)的矩形。

如图2-2-3(a) 所示。

如图2-2-3 矩形R中点的稀疏性若矩形R中有多于6个S中的点,则由鸽舍原理易知至少有一个(d/2)*(2d/3)的小矩形中有2个以上S中的点。

设u,v是这样2个点,它们位于同一小矩形中,则(x(u)-x(v))2+(y(u)-y(v))2 ≤(d/2)2+(2d/3)2=25/36d2因此,distance(u,v) ≤5d/6<d。

这与d的意义相矛盾。

也就是说矩形R中最多只有6个S 中的点。

图2-2-3(b)是矩形中恰有6个S中点的极端情形。

由于这种稀疏性质,对于P1中任意一点p,P2中最多只有6个点与它构成最接近点对的候选者。

因此,在递归法的合并步骤中,我们最多只需要检查6*n/2=3n个候选者,而不是n2/4个候选者。

我们将p和P2中所有S2 的点投影到垂直线L上。

由于能与p点一起构成最接近点对候选者的S2 中点一定在矩形R中,所以它们在直线L上的投影点距p在L上投影点的距离小于d。

由上面的分析可知,这种投影点最多只有6个。

因此,若将P1和P2中所有S中点按其y坐标排好序,则对P1中所有点,对排好序的点列做一次扫描,就可以找出所有最接近点对的候选者。

对P1中每一点最多只要检查P2中排好序的相继6个点。

至此,我们给出用递归法求二维点集最接近点对的算法Cpair 2 如下:------------------------------------------------------------------------------------------------bool Cpair 2(S,d){N=|S|;If(n<2){d=∞;Return false;}1. m=S中各点x间坐标的中位数;构造S1和S2 ;//S1={p∈S| x(p)<=m},S2 ={ p∈S| x(p)>m }2. Cpair 2(S1,d1);Cpair 2(S2 ,d2);3. dm=min(d1,d2);4. 设P1是S1中距垂直分割线L的距离在dm之内的所有点组成的集合;P2是S2 中距分割线L的距离在dm之内所有点组成的集合;将P1和P2中点依其y坐标值排序;并设X和Y是相应的已经排好序的点列;5. 通过扫描X以及对于X中每个点检查Y中与其距离在dm内的所有点(最多6个)可以完成合并;当X中的扫描指针逐次向上移动时,Y中的扫描指针可在宽为2dm的一个区间内移动;设dl是按这种扫描方式找到的点对间的最小距离;6. d=min(dm,dl);return true;}------------------------------------------------------------------------------------------------------2.3 算法优化在以上二维情形下的算法中,在每次执行第4步时都要进行排序,这将花费较多的时间,从而增加算法的复杂度。

因此,在这里我们要作一个技术处理。

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

在执行递归法的第4步时,只要对P*作一次线性扫描,即可抽取出我们所需要的排好序的点列X和Y。

然后,在第5步时再对X作一次线性扫描,即可求得dl。

2.4 算法实现在具体实现算法Cpair 2时,我们分别用类Point X和Point Y表示依x坐标和依y坐标排序的点。

-----------------------------------------------------------------------------------------Class Point X{Public:Int operator<=(Point X a) const{return (x<=a.x);}Private:Int ID; //点编号Float x,y; //点坐标};Class Point Y{Public:int operator<=(Point Y a) const{return (y<=a.y)}Private:Int p; //同一点在数组X中的坐标Float x,y; //点坐标};--------------------------------------------------------------------------------------------平面上任意两点u和v之间的距离可计算如下:---------------------------------------------------------------------------------------------Template <class Type>Inline float distance(const Type & u,const Type & v){Float dx=u.x-v.x;Float dy=u.y-v.y;Return sqrt(dx * dx + dy * dy);}------------------------------------------------------------------------------------------------在算法Cpair 2中,用数组X存储输入的点集。

相关文档
最新文档