最接近点对问题实验报告

合集下载

最接近点对问题实验报告

最接近点对问题实验报告

最接近点对问题一.实验目的:1.理解算法设计的基本步骤及各步的主要内容、基本要求;2.加深对分治设计方法基本思想的理解,并利用其解决现实生活中的问题;3.通过本次实验初步掌握将算法转化为计算机上机程序的方法。

二.实验内容:1.编写实现算法:给定n对点,在这n对点中找到距离最短的点对。

2.将输出数据存放到另一个文本文件中,包括结果和具体的运行时间。

3.对实验结果进行分析。

三.实验操作:1.最接近点对查找的思想:首先,将所有的点对按照x坐标排序,找到x坐标的中位数,将所有的点对分成三部分,横坐标小于x(S1)、等于x(S2)和大于x(S3)的点对,在求取每部分中的最短距离,利用分治法,一步步地分解为子问题,找到最短距离d。

由于距离最近的两个点可能在不同的区域中,需要进一步判断。

选择S1中的一个点,由于与它相比较的点的距离不可能超过d,故其配对范围为d*2d的矩形,将这个矩形划分为6份2/d*3/d的小矩形,其对角线的长度为5/6d,小于d,故S1中的任意一个点只需和S2中的6个点比较即可,最终确定最短的距离。

2.取中位数:为了减少算法的时间开销,需要将所有的点对进行分组,以中位数为基准,考虑到快速排序的不稳定性,本次排序使用了合并排序。

代码实现:template <class Type>void Merge(Type c[],Type d[],int l,int m,int r){int i = l,j = m + 1,k = l;while((i<=m)&&(j<=r)){if(c[i]<=c[j]) d[k++] = c[i++];else d[k++] = c[j++];}if(i>m) {for(int q=j; q<=r; q++) d[k++] = c[q];}else{for(int q=i; q<=m; q++) d[k++] = c[q];}}template <class Type>void MergeSort(Type a[],Type b[],int left,int right){if(left<right){int i = (left + right)/2;MergeSort(a,b,left,i);MergeSort(a,b,i+1,right);Merge(a,b,left,i,right);//合并到数组aCopy(a,b,left,right);//复制回数组a}}3.数据存入文件:本次对文件的输入没有存入文本文件中,只将输出数据输入到指定的文件夹中,用到了输出流文件。

最近点对问题

最近点对问题

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

如何写实验报告(共5篇)

如何写实验报告(共5篇)

篇一:怎么写生物实验报告实验报告一般分为以下几个部分:一、实验名称。

二、实验原理。

将该实验的主要原理用简明扼要的语言进行归纳总结。

三、实验仪器和材料。

如果所用仪器和材料较多,可写重要的部分,常用的可以不写。

四、实验步骤。

该实验如何操作的,方法和顺序。

可以用方框图表示,这样一目了然。

五、实验结果。

将该实验最后结果用文字或图表的方式进行表达。

推荐用表格或图进行表示。

要注意将度量单位写清楚。

六、实验讨论。

该部分主要对上述实验结果进行讨论。

有的是对实际操作中实验现象或结果和实验指导不一致的原因进行讨论,有的是对实际操作中产生的实验现象的原理或原因进行讨论,有的是对实际操作中可以改进的方法进行讨论,有的是对该实验的进一步应用进行讨论等等。

篇二:如何写实验报告如何写实验报告以书面形式交流你的研究结果是任何科学探索的必要组成部分。

除了书面交流外,常常还需要口头交流。

实验报告与正式发表研究论文的写作形式略有不同。

撰写实验报告是改善写作技巧,提高逻辑思维、分析思维和批判思维能力的非常有效的方式。

即使本课程的部分学生将来可能不从事科学研究工作,但是写作和思维技巧对任何行业都是重要的。

一个好的实验报告应是简洁的、组织良好的、有逻辑的和完整的。

图片已关闭显示,点此查看图片已关闭显示,点此查看图片已关闭显示,点此查看图片已关闭显示,点此查看图片已关闭显示,点此查看图片已关闭显示,点此查看实验报告写作应该遵循下面的格式,包括六个部分。

这与大部分用于发表的科研报告的格式大致相同,只是略有变化。

题目题目要简洁、清楚、切中主题。

题目占一行,位于中间。

在题目下面写出实验者姓名,实验内容的名称,实验时间,同组同学姓名。

同组同学可用一个报告题目。

引言本部分解释为什么做这个研究。

在引言中必须清楚的提出一个问题和陈述你要证实的假设。

通常从观察开始,发现问题,然后提出假设。

例如,你发现外面有的植物叶片变黄,你想知道是否影响光合作用。

你想用测定不同绿色叶片的叶绿素含量和光合速率的方法来检验你的想法。

全站仪点放样实验报告(5篇)

全站仪点放样实验报告(5篇)

全站仪点放样实验报告(5篇)学生现在学习的内容是为以后的进展奠定根底,是丰富自己的文化学问,是自己能够成为一个对社会,对国家有用的人才,但是现在我们所学的学问大多只是理论上的东西,为此我们应当将理论和实际联系起来,积极参与实际工程,这次为期20天的实习教会了我们如何将自己所学的学问应用于实际工程工程之中,懂得了解决一些实际问题的k“ href=“/Special/xuexifangfa/“ target=“_blank“方法,对增加自己的生活和工作经受有很大益。

同时也可以说这次工作是对同学的一次考念,在实习过程中有的同学虽然生病但是依旧坚持工作,可以说着种精神是相当名贵的。

通过这次野外工程实习,加强了自身把握数字测图外业数据采集方法与内业作图方法,更加深刻的理解了数字测图在野外的运用,数字测图带来的不但是数据采集速度的提高,工作效率的增加,更加减轻了工作人员的工作强度;明白了在数据采集过程中应当留意的问题,使自己在课堂上学到的学问得到了在实际中的运首先,通过实习,让我发觉我在平常学习中存在的许多学问漏洞。

课本上介绍仪器使用的学问都比拟抽象,到了真正实践中的时候,我们未能很好把书本学问应用到实践中,还需要教师再次进展指导。

在近距离的接触这些实物,能我更坚固的把握相关的学问点;也能令我提高对仪器的操作的娴熟、精准程度(比方能够快速对中整平)。

全站仪点放样试验报告二首先感谢学校和教师给以了我这次参与工程实践的时机,在这次20多天的实习过程中,经过这次实习,无论在心理上还是在生理上都得到了很好的熬炼,全站仪测量实习报告。

学生现在学习的内容是为以后的进展奠定根底,是丰富自己的文化学问,是自己能够成为一个对社会,对国家有用的人才,但是现在我们所学的学问大多只是理论上的东西,为此我们应当将理论和实际联系起来,积极参与实际工程,这次为期20天的实习教会了我们如何将自己所学的学问应用于实际工程工程之中,懂得了解决一些实际问题的方法,对增加自己的生活和工作经受有很大好处,实习报告《全站仪测量实习报告》。

最近点对算法 C++

最近点对算法 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.实验总结:从本次试验中得到的领悟是:分治法事把问题分解成两个相似小问题,子问题和原来的大问题解决方法一样所以可以用递归,分治法重要是找到递归出口,什么时候递归结束,一般都有元素个数的限制。

算法——蛮力法之最近对问题和凸包问题

算法——蛮力法之最近对问题和凸包问题

算法——蛮⼒法之最近对问题和凸包问题 上次的博客写到⼀半宿舍停电了。

然⽽今天想起来补充完的时候发现博客园并没有⾃动保存哦,微笑。

最近对问题 ⾸先来看最近对问题,最近对问题描述的就是在包含n个端的集合中找到距离最近的两个点,当然问题也可以定义在多维空间中,但是这⾥只是跟随书上的思路实现了⼆维情况下的最近对问题。

假设所有讨论的点是以标准的笛卡尔坐标形式(x,y)给出的,那么在两个点P i=(X i,Y i)和P j=(X j,Y j)之间的距离是标准的欧⼏⾥得距离: d(P i,P j)=sqrt( (X1-X2)2+(Y1-Y2)2 )蛮⼒法的思路就是计算出所有的点之间的距离,然后找出距离最⼩的那⼀对,在这⾥增加效率的⼀种⽅式是只计算点下标 i<j 的那些对点之间的距离,这样就避免了重复计算同⼀对点间距离。

下⾯是蛮⼒法解决最近对问题的算法:使⽤蛮⼒法求平⾯中距离最近的两点BruteForceClosetPoints(P)//输⼊:⼀个n(n≥2)的点的列表P,P i=(X i,Y i)//输出:距离最近的两个点的下标index1和index2dmin <— ∞for i <— 1 to n-1 do for j <— i+1 to n do d <— sqrt( (X i-X i)2+(Y j-Y j)2 ) if d<dmin dmin=d; index1=i; index2=j;return index1,index2 该算法的关键步骤是基本操作虽然是计算两个点之间的欧⼏⾥得距离,但是求平⽅根并不是像加法乘法那么简单。

上⾯算法中,开平⽅函数导数恒⼤于0,它是严格递增的,因此我们可以直接只计算(X i-X i)2+(Y j-Y j)2,⽐较d2的⼤⼩关系,这样基本操作就变成了求平⽅。

平⽅操作的执⾏次数是: n(n-1)∈Θ(n2)因此,蛮⼒法解决最近对问题的平均时间复杂度是Θ(n2) 下⾯是该算法的c++代码实现部分,在实现这个算法时,我碰到了三个问题: ⼀是:怎么表⽰⼀个点集,因为最终返回的下标是集合中点的下标,要⽤的数据结构就是⼀维数组,但是点的xy坐标⼜要怎么表⽰呢,这⾥我在头⽂件中创建了struct类型的点结构,该结构拥有的成员变量就是x代表的横坐标和y代表的纵坐标,这样就可以直接创建该结构的⼀位数组进⾏计算了。

最近点对算法

最近点对算法

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

最接近点对问题
一.实验目的:
1.理解算法设计的基本步骤及各步的主要内容、基本要求;
2.加深对分治设计方法基本思想的理解,并利用其解决现实生活中的问题;
3.通过本次实验初步掌握将算法转化为计算机上机程序的方法。

二.实验内容:
1.编写实现算法:给定n对点,在这n对点中找到距离最短的点对。

2.将输出数据存放到另一个文本文件中,包括结果和具体的运行时间。

3.对实验结果进行分析。

三.实验操作:
1.最接近点对查找的思想:
首先,将所有的点对按照x坐标排序,找到x坐标的中位数,将所有的点对分成三部分,横坐标小于x(S1)、等于x(S2)和大于x(S3)的点对,在求取每部分中的最短距离,利用分治法,一步步地分解为子问题,找到最短距离d。

由于距离最近的两个点可能在不同的区域中,需要进一步判断。

选择S1中的一个点,由于与它相比较的点的距离不可能超过d,故其配对范围为d*2d的矩形,将这个矩形划分为6份2/d*3/d的小矩形,其对角线的长度为5/6d,小于d,故S1中的任意一个点只需和S2中的6个点比较即可,最终确定最短的距离。

2.取中位数:
为了减少算法的时间开销,需要将所有的点对进行分组,以中位数为基准,考虑到快速排序的不稳定性,本次排序使用了合并排序。

代码实现:
template <class Type>
void Merge(Type c[],Type d[],int l,int m,int r){
int i = l,j = m + 1,k = l;
while((i<=m)&&(j<=r)){
if(c[i]<=c[j]) d[k++] = c[i++];
else d[k++] = c[j++];
}
if(i>m) {
for(int q=j; q<=r; q++) d[k++] = c[q];
}
else{
for(int q=i; q<=m; q++) d[k++] = c[q];
}
}
template <class Type>
void MergeSort(Type a[],Type b[],int left,int right){
if(left<right){
int i = (left + right)/2;
MergeSort(a,b,left,i);
MergeSort(a,b,i+1,right);
Merge(a,b,left,i,right);//合并到数组a
Copy(a,b,left,right);//复制回数组a
}
}
3.数据存入文件:
本次对文件的输入没有存入文本文件中,只将输出数据输入到指定的文件夹中,用到了输出流文件。

代码实现:
ofstream outFile;
outFile.open("E://程序设计/practice 1/算法设计与分析/文本文
件夹/最接近点对问题结果.txt",ios::trunc);
int length;
cout<<"请输入点对数:";
cin>>length;
xPosition X[M];
cout<<"随机生成的二维点对为:"<<endl;
outFile<<"随机生成的二维点对为:\n";
for(int i=0;i<length;i++){
X[i].ID=i;
X[i].x=Random();
X[i].y=Random();
cout<<"("<<X[i].x<<","<<X[i].y<<") ";
outFile<<"("<<X[i].x<<","<<X[i].y<<") \n";
}
xPosition a;
xPosition b;
float d;
start=clock();
Cpair2(X,length,a,b,d);
finish=clock();
cout<<endl;
cout<<"最邻近点对为:("<<a.x<<","<<a.y<<")和
("<<b.x<<","<<b.y<<") "<<endl;
outFile<<"最邻近点对为:("<<a.x<<","<<a.y<<")和
("<<b.x<<","<<b.y<<") \n";
cout<<"最邻近距离为: "<<d<<endl;
outFile<<"最邻近距离为: "<<d<<"\n";
cout<<"程序运行时间:"<<finish-start<<endl;
outFile<<"程序运行时间:"<<finish-start;
outFile.close();
4.求解最短距离:
将总的点对分为三部分,对每一部分求解最短的距离,对只有两对、三对的情况直接进行距离求解。

当对每一部分求解最短距离时,采用分治法分解为一个个小的子问题,
对点在两个区域的情况,依照思想,进行排序比较,和已有的最短距离比较,最终确定最短距离的点对。

代码实现:
void closest(xPosition X[],yPosition Y[],yPosition Z[],int
left,int right,xPosition& a,xPosition& b,float& d){
if(right-left==1) //两点的情形
{
a=X[left];
b=X[right];
d=dis(X[left],X[right]);
return;
}
if(right-left==2) //3点的情形
{
float d1=dis(X[left],X[left+1]);
float d2=dis(X[left+1],X[right]);
float d3=dis(X[left],X[right]);
if(d1<=d2 && d1<=d3){
a=X[left];
b=X[left+1];
d=d1;
return;
}
if(d2<=d3){
a=X[left+1];
b=X[right];
d=d2;
}
else{
a=X[left];
b=X[right];
d=d3;
}
return;
}
//多于3点的情形,用分治法
int m=(left+right)/2;
int f=left,g=m+1;
for(int i=left;i<=right;i++){
if(Y[i].p>m) Z[g++]=Y[i];
else Z[f++]=Y[i];
}
closest(X,Z,Y,left,m,a,b,d);
float dr;
xPosition ar,br;
closest(X,Z,Y,m+1,right,ar,br,dr);
{
a=ar;
b=br;
d=dr;
}
Merge(Z,Y,left,m,right);//重构数组Y
int k=left;
for(int i=left;i<=right;i++){
if(fabs(X[m].x-Y[i].x)<d){
Z[k++]=Y[i];
}
}
//搜索Z[l:k-1]
for(int i=left;i<k;i++){
for(int j=i+1;j<k && Z[j].y-Z[i].y<d;j++){
float dp=dis(Z[i],Z[j]);
if(dp<d){
d=dp;
a=X[Z[i].p];
b=X[Z[j].p];
}
}
}
}
四.实验数据分析:
本实验对不同规模的数据进行测试,实验数据如下。

五.实验感受:
在实验中,随机生成一定数量的点对,对这些点对进行最短距离求解,由于设置的范围过小,在进行时间测量时,得到的数据都为零,故在进行实际分析时,需要使用大规模的数据。

相关文档
最新文档