当前位置:文档之家› 最近点对问题

最近点对问题

最近点对问题
最近点对问题

算法分析与设计最近对问题

最近对问题

问题描述:

在二维平面上的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

#include

#include

#define NUM 1000

typedef 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

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

datax[i] = data[i].x;

datay[i] = data[i].y;

}

for(i = 0;i

for(j = i+1;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);

else

fprintf(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 中。

MergeSort(data,NUM,0);

// 分治法

dis = shortestDis(data,NUM,&n1,&n2);

printf("分治法:\n");

printf("%f\nX:%d\tY:%d\nX:%d\tY:%d\t",dis,n1.x,n1.y,n2.x,n2.y);

// 蛮力法

computeShortestDistance(data,NUM,re);

printf("\nx:%d\ty:%d\nx:%d\ty:%d",re[0],re[1],re[2],re[3]);

}

实验环境:

Codeblocks

编译器:MinGW(Minimalist GNU for Windows)

实验结果:

心得体会:

1. 在课堂上听了老师讲解算法之后,自己在亲自动手实现算法之后,对算法有了更深的理解。

2. 在算法的实现过程中遇到了一些小问题,但是都通过自己google 解决了。

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

迭代最近点算法综述

迭代最近点算法综述 摘要:三维点集配准问题是计算机技术中的一个极其重要的问题,作为解决三维点集配准问题的一个应用较为广泛的算法,ICP算法得到了研究者的关注,本文以一种全新的思路从配准元素的选择、配准策略的确定和误差函数的求解等3个方面对三维点集配准的ICP算法的各种改进和优化进行了分类和总结。 关键词:三维点集;迭代最近点;配准 1引言 在计算机应用领域,三维点集配准是一个非常重要的中间步骤,它在表面重建、三维物体识别、相机定位等问题中有着极其重要的应用[1]。对于三维点集配准问题,研究者提出了很多解决方案,如点标记法、自旋图像、主曲率方法、遗传算法、随机采样一致性算法等等,这些算法各有特色,在许多特定的情况下能够解决配准的问题。但是应用最广泛的,影响最大的还是由Besl和Mckay在1992年提出的迭代最近点算法[2](Iterative Closest Point,ICP),它是基于纯粹几何模型的三维物体对准算法,由于它的强大功能以及高的精确度,很快就成为了曲面配准中的主流算法。 随着ICP算法的广泛应用,许多研究者对ICP算法做了详细的研究,分析了该算法的缺陷和特点,提出了许多有价值的改进,推动了这一重要算法的发展。本文着眼于ICP算法的发展历程,详细介绍了ICP算法的基本原理,总结其发展和改进的过程,对于该算法的各个阶段的发展和变化做了简单的论述。 2ICP算法原理 2.1ICP算法原理 ICP算法主要用于三维物体的配准问题,可以理解为:给定两个来至不同坐标系的三维数据点集,找出两个点集的空间变换,以便它们能进行空间匹配。假定用{}表示空间第一个点集,第二个点集的对齐匹配变换为使下式的目标函数最小[3]。 ICP算法的实质是基于最小二乘法的最优匹配算法,它重复进行“确定对应关系点集—计算最优刚体变换”的过程,直到某个表示正确匹配的收敛准则得到满足。ICP 算法的母的是找到目标点集与参考点之间的旋转R和平移T变换,使得两匹配数据中间满足某种程度 度量准则下的最优匹配。假设目标点集P的坐标为{}及参考点集Q的坐标为

第65讲 凸集与凸包(原)

第65讲凸集与凸包 本节主要内容是:凸集、凸包的概念以及用凸集凸包来解有关的题.凸集:平面上的点集,如果任何两点在这个点集内,则连这两点的线段上的所有的点也在此点集内,就说该点集是一个凸集. 线段、射线、直线、圆及带形、整个平面等都是凸集. 两个凸集的交集还是凸集;任意多个凸集的交集也仍是凸集. 凸包:每个平面点集都可用凸集去盖住它,所有盖住某个平面点集的凸集的交集就是这个平面点集的凸包. 或者可以形象地说:如果把平面上的点集的每个点都插上一根针,然后用一根橡皮筋套在这些针外,当橡皮筋收紧时橡皮筋围出的图形就是这个点集的凸包. 平面点集的直径平面点集中的任意两点距离的最大值称为这个平面点集的直径. 例如,圆的直径就是其直径,有无数条;线段的直径就是其本身;正三角形的三个顶点组成的点集的直径就是其边长,有三条;平行四边形的直径是其较长的对角线;…. A类例题 例1定理任何一个平面点集的凸包是存在且唯一的. 分析存在惟一性的证明,即证明满足某条件的集A存在且惟一存在.通常先证明存在性,即证明有满足条件的集合A.再用反证法证明惟一性,即若满足条件的集A不惟一,或说明会引出矛盾,或得出其余集均必需与A相等的结论. 证明由于全平面是一个凸集,故任何平面点集都可用全平面盖住,即能被凸集盖住,从而盖住该凸集的所有凸集的交集存在,即凸包存在.而如果某个凸集A有两个凸包M1与M2,则M1∩M2也能盖住凸集A,且M1∩M2?M1,但M1是A的凸包,故M1?M1∩M2,故M1∩M2=M1.同理M1∩M2=M2.即M1=M2.

例2 定理 如果一个点集M 是由有限个点组成,且其中至少有三个点不共线,则M 的凸包是一个凸多边形. 分析 可以构造一个寻找凸包的方法,来说明命题的正确性. 证明 由于M 为有限点集,故存在一条直线l ,使M 中的一个或几个点在l 上,其余的点 都在l 同旁(这只要任画一条直线,如果点集M 中的点在直线l 的两旁,则让直线按与此直线垂直的方向平移,即可得到满足要求的直线). 取l 上的两个方向中的一个方向为正向,此时,按此正向,不妨设M 中不在l 上的点都 在l 的左边.在l 上沿其正向找出M 中的最后一个点A 1,把l 绕A 1逆时针旋转,直到遇到M 中的另外的点,又找出此时l 上的M 中的最后一个点A 2,此时再让l 绕A 2逆时针旋转,依此类推,直到最后绕A k 旋转又遇到A 1为止(由于M 是有限点集,故这样的旋转不可能一起下去).这时,凸多边形A 1A 2…A k 即为M 的凸包. 情景再现 1.证明圆面(圆及圆内所有的点组成的集合)是凸集. 2.平面上任意给定5个点,其中任三点不共线,则可选出4个点,这四点能构成一个凸四边形的四个顶点. B 类例题 例3 海莱定理: 定理(海莱定理) 对于若干个(个数n ≥3)凸集,如果任意三个凸集都有一个公共点,那么存在一个点同时属于每个凸集. 分析 先证明简单情况,再用数学归纳法证明本定理. 证明 对于n =3,显然成立. 当n >3时,先取4个这样的凸集.F 1,F 2,F 3,F 4. A A A A 123k l l 1

算法实验四_空间最近点对算法

一、算法分析 该算法的问题描述为:给定二维平面上的点集,求解距离最近的两个点,并计算出两点间的距离。 解决问题最初的思路为穷举法。对所有两点间的组合计算其距离。然后对其进行比较,找出最小值即可。不过这样做的缺点是时间复杂度和空间复杂度十分庞大,消耗巨量资源。如有n个点的平面上,计算的复杂度能达到n*n。因此设计出一个高效的算法来代替穷举法是有现实意义的。 在思考问题的过程中,可以考虑使用分治法的思想,以x,y中x坐标作为划分区间的标准。将平面点集一分为二。求解其中的最小点对。由此产生的问题为划分点附近两个区间中两点的距离可能小于各自区间中的最小值,产生了纰漏。因此在在分治的过程中,加入分界线附近的点对最小值求解函数。分界线区域内区间的选取标准为d。其中d为左半区间和右半区间的最小值中的较小值。在具体实现中,首先建立一个空数组存放按y坐标排序的点集,判断两个相邻点之间的y坐标差值,若大于d,则两点间距离一定大于d,可以直接跳过,继续判断下一个点对。若小于d,则继续计算两点间的实际距离,若大于d,则跳过,小于d,将最小值更新为该点对距离。 二、算法实现 该算法的具体实现使用了两种求解方法,穷举法和分治法。其中,穷举法用于判断最近点对算法实现结果的正确性。 算法使用的数据结构为数组,其中为了简单起见,将x轴坐标与y轴坐标分别存入两个数组,并新建一个数组record[],记录数组y的元素下标,用于绑定x坐标对应的y坐标。 在设计过程中使用到了比较排序算法,用于对x及y坐标排序,这并不增加其时间复杂度。因此是可行的。 在分治算法中,设置划分区间的下限为3,即当区间内元素个数小于等于3时,不再使用分治。在该设定下分为三种情况,元素数为1时,Min设为无穷。元素数为2时,计算两点间距离并返回。元素数为3时,一共计算三次距离,并取其最小值。

最近点对分治法

假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。 如果不用分治法,问题非常容易解决。也就是蛮力法。 代码如下: #include #include typedef struct TYPE { double x, y; } Point; float dist(Point a,Point b) { return (float)sqrt((float)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } float nearest(Point* points, int n) { float temp,near1=10000; int i,j; if(n==1) { printf("不可能"); return 0; } else{ for(i=0; itemp)?temp:near1; } } return near1; } } int main()

{ int n, i; double d; printf("输入点的个数:"); scanf("%d", &n); Point a[10000]; while (n) { for (i = 0; i < n; i++) scanf("%lf%lf", &(a[i].x), &(a[i].y)); d = nearest(a,n); printf("%.2lf\n", d); scanf("%d", &n); } return 0; } 但是本题是用分治法,我也参考了网上很多资料,他们要求对纵坐标进行排序,可能是为了对求右边的问题的点扫描用for 循环,但我发现那算法就不对,但愿是我的还没有完全明白按纵坐标排序的原因, 我参考的资料: https://www.doczj.com/doc/6b14551025.html,/p-198711591.html?qq-pf-to=pcqq.c2c 代码如下: #include #include #include

分治法实验报告一

宁波工程学院电信学院计算机系 实验报告 课程名称:算法设计与分析实验项目:用分治法算法解 最接近点对问题 指导教师:崔迪 实验位置:软件工程实验室姓名: 班级: 学号: 日期: 2016/10/12 一、实验目的 通过上机实验,要求掌握分治法算法的问题描述、算法设计思想、程序设 计和算法复杂性分析等。 二、实验环境: Eclipse 三、实验内容:用分治法解最接近点对问题 (1)问题描述 给定平面S上n个点,找其中的一对点,使得在n(n-1)/2 个点对中,该 点对的距离最小。 (2)算法设计思想 1. n较小时直接求 (n=2). 2.将S上的n个点分成大致相等的2个子集S1和S2 3.分别求S1和S2中的最接近点对 4.求一点在S1、另一点在S2中的最近点对 5.从上述三对点中找距离最近的一对.

(3)程序设计(程序清单及说明) package closestpair; import java.util.Arrays; import https://www.doczj.com/doc/6b14551025.html,parator; import java.util.Random; import java.util.Scanner; //定义坐标点 class Point { double x; double y; public Point(double x, double y) { this.x = x; this.y = y; } } // 根据x坐标排序 class MyComparatorX implements Comparator { @Override public int compare(Point p1, Point p2) { if (p1.x < p2.x) { return -1; } else if (p1.x > p2.x) { return 1; } else { return 0; } } } // 根据Y坐标排序 class MyComparatorY implements Comparator { @Override public int compare(Point p1, Point p2) { if (p1.y < p2.y) { return -1; } else if (p1.y > p2.y) { return 1; } else {

最接近点对问题实验报告

最接近点对问题 一.实验目的: 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 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 void MergeSort(Type a[],Type b[],int left,int right){ if(left

最近点对问题

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

算法导论求n个点的最小距离

算法导论求n个点的最小距离 2010-01-20 17:23 在中文算法导论649页 算法: 0:把所有的点按照横坐标排序 1:用一条竖直的线L将所有的点分成两等份 2:递归算出左半部分的最近两点距离d1,右半部分的最近两点距离d2,取 d=min(d1,d2) 3:算出“一个在左半部分,另一个在右半部分”这样的点对的最短距离d3。4:结果=min(d1,d2,d3) 关键就是这第3步。貌似这需要n^2的时间,把左边每个点和右边每个点都对比一下。其实不然。秘密就在这里。 首先,两边的点,与分割线L的距离超过d的,都可以扔掉了。 其次,即使两个点P1,P2(不妨令P1在左边,P2在右边)与分割线L的距离(水平距离)都小于d,如果它们的纵坐标之差大于d,也没戏。 就是这两点使得搜索范围大大减小: 对于左半部分的,与L的距离在d之内的,每个P1来说:右半部分内,符合以上两个条件的点P2最多只有6个! 原因就是: d是两个半平面各自内,任意两点的最小距离,因此在同一个半平面内,任何两点距离都不可能超过d。 我们又要求P1和P2的水平距离不能超过d,垂直距离也不能超过d,在这个d*2d 的小方块内,最多只能放下6个距离不小于d的点。 因此,第3步总的比较距离的次数不超过n*6。 第3步的具体做法是: 3.1 删除所有到L的距离大于d的点。 O(n) 3.2 把右半平面的点按照纵坐标y排序。 O(nlogn) 3.3 对于左半平面内的每个点P1,找出右半平面内纵坐标与P1的纵坐标的差在d以内的点P2,计算距离取最小值,算出d3。 O(n*6) = O(n) 因为3.2的排序需要O(nlogn), 所以整个算法的复杂度就是O(n((logn)^2))。 改进:

寻找最近点

寻找最近点 维果斯基根据儿童现有心理机能的发展水平和儿童在成人的指导、帮助下所达到的解决问题的水平两者的界说,提出了“最近发展区”这一概念,这也充分说明了教育的重要性。那么,在这其中扮演举足轻重的角色者就是教师。作为教师,应当尽力弄清每个孩子的最近发展区,在教学过程中,通过提问或设计一定的情境,寻找孩子发展的最近点来促使学生向认知发展的潜在水平发展,促进儿童跨越其最近发展区,从而提高儿童认知的成长与发展。这在平时的学科教学中经常使用。 在教学“五光十色”这个词语时,因为在平时,孩子经常看到这个词语,甚至也运用过,所以当老师提出:五光十色是什么意思时?有一些优等生马上就能说出意思了。但往往有一部分学生只能理解到“有许多种颜色”这一层面。 我接着问:“五光十色仅仅指颜色多吗?”说话中,我把“光”字读得特别重。 “还有光泽呢!” “对,很好!那么五光十色整个词语的意思是什么呢?” “五光十色是指颜色丰富,色泽鲜艳。” “那么你能用五光十色说句话吗?” 一部分同学已经能跟着老师的思路举手回答问题了,可是有一些后进生仍然停留在字意的理解上。 这时,我盯着他们的眼睛问:“你在哪里看到过五光十色的现象?” 几个后进生恍然大悟,终于也举起了手。

“肥皂泡在阳光下五光十色,美丽极了!” “城市的夜晚是一个五光十色的世界,美丽极了!” “走进灯展区,我的周围五光十色,看得我眼花缭乱!” …… 从这儿可以发现,最近发展区存在着个别差异和情景差异。对于一些优等生,老师提出的要求完全在他们的实际发展水平之内,他们能自行解决这些问题。对于一些后进生,需要教师的启发、帮助或设置一定的情境,在这个“最近发展区”之内理解和运用这个词语,确实,教师应该敏锐地为孩子寻找最近点,以达到孩子实际水平的提高和发展。 柴飞梅 2005/06/09

Bullet中最近点距离算法

Bullet中最近点距离算法 在Bullet中,通过类btVoronoiSimplexSolve实现了1到4个顶点的单纯形到原点的距离计算,该类可以在GJK算法中调用,用以代替Johnson distance algorithm[我们前篇文章原点到四面体的距离,实际上就是介绍该算法]算法。 本文我们研究bullet中如何实现该类以及该类的用法。 首先我们看看顶点在btVoronoiSimplexSolve中是什么存储的: 用到了三个变量: btVector3 m_simplexVectorW[VORONOI_SIMPLEX_MAX_VERTS]; btVector3 m_simplexPointsP[VORONOI_SIMPLEX_MAX_VERTS]; btVector3 m_simplexPointsQ[VORONOI_SIMPLEX_MAX_VERTS]; m_simplexVectorW中存放的是单纯形的顶点,m_simplexVectorP, m_simplexVectorQ中存放的是两个物体中和单纯形顶点m_simplexVectorW相对应的顶点,注意,这儿单纯形表示是明可夫斯基差形状中的单纯形,所以m_simplexVectorP, m_simplexVectorQ就是表示两个物体中的顶点,并且m_simplexVectorP - m_simplexVectorQ = m_simplexVectorW。(都是世界坐标系中的值) 该类中计算机单纯形到原点距离通过函数closest计算,该函数又调用函数updateClosestVectorAndPoints具体实施。下面我看看updateClosestVectorAndPoints中的代码: 1、一个顶点的单纯形 1 case1://一个顶点 2 { 3m_cachedP1 = m_simplexPointsP[0];

用分治法求解棋盘覆盖问题

棋盘覆盖问题 问题描述: 在一个2k ×2k (k ≥0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格。显然,特殊方格在棋盘中出现的位置有4k 中情形,因而有4k 中不同的棋盘,图(a )所示是k=2时16种棋盘中的一个。棋盘覆盖问题要求用图(b )所示的4中不同形状的L 型骨牌覆盖给定棋盘上除特殊方格以外的所有方格,且热河亮哥L 型骨牌不得重复覆盖。 问题分析: K>0时,可将2k ×2k 的棋盘划分为4个2k-1×2k-1的子棋盘。这样划分后,由于原棋盘只有一个特殊方格,所以,这4个子棋盘中只有1个子棋盘中有特殊方格,其余3个子棋盘中没有特殊方格。为了将这3个没有特殊方格的子棋盘转化成为特殊棋盘,以便采用递归方法求解,可以用一个L 型骨牌覆盖这3个较小的棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种划分策略,直至将棋盘分割为1×1的子棋盘。 问题求解: 下面介绍棋盘覆盖问题中数据结构的设计。 (1) 棋盘:可以用一个二维数组board[size][size]表示一个棋盘,其中size=2k 。为了 在递归处理的过程中使用同一个棋盘,将数组board 设为全局变量。 (2) 子棋盘:整个棋盘用二维数组board[size][size]表示,其中的子棋盘由棋盘左上 角的下标tr 、tc 和棋盘大小s 表示。 (3) 特殊方格:用board[dr][dc]表示特殊方格,dr 和dc 是该特殊方格在二维数组 board 中的下标。 (4) L 型骨牌:一个2k ×2k 的棋盘中有一个特殊方格,所以,用到L 型骨牌的个数 为(4k -1)/3,将所有L 型骨牌从1开始连续编号,用一个全局变量tile 表示。 图(b ) 图 (a )

打凸包

凸包成形 (1)高凸包成形方法: 在MB板等产品上经常可以看到一些高度较高的凸包,如图(A)所示。 (2). 成形方法 产品的凸包高度(H)比较高,在一次抽凸成形时容易拉破。为了避免发生拉破现象 保证产品成形以后的形状尺寸,一般要分两步成形。 第一步:抽弧形。如上图(B),注意以下几个重点: A. 产品抽弧成形后的c和d两点间的周长L1(由三段弧长相加)应稍大于产品要求的 断面中a和b两点间的周长L2(a和b参见图A),一般L1=L2+(0.2~0.8)mm. B. 下模入子c和d两点间的直线距离等于产品要求的断面中a和b两点间的直线距离D5。 C. 闭模时保证图中半径为r1的圆弧与下模最小间隙为产品材料厚度的百分之六十(T*60%)。 第二步:整形。 有两种不同的整形方法。如图(C)和图(D),一般用图(C)方法,凸包外形要求不高 时用图(D) 方法 (3). 确定抽弧形时冲子尺寸的步骤和方法: A. 根据产品要求的形状和尺寸确定下模入子内孔的形状尺寸。如图(E) 注意:a.C和d点间的直线距离等于产品要求的断面中a和b两点的直线距离D5。 b.入子内孔中圆弧半径r1的大小一般在1~3mm之间(含1和3mm),以0.5mm 为一阶。初步确定取r1等于产品断面中相应处的半径r.

B. 初步产品抽弧形时的外形尺寸: a. 如图(f)所示,以3点(下与下模入子内孔两r1圆弧的切点及抽凸底部的中点(g)作圆。

b. 经过修剪如图(g)所示,测出点c和点d间三段圆弧的总长度L1。 c. 如果此三段弧总长L1小于产品要求的断面中a和b两点间的周长L2,则通过把抽凸底部中点g向下移动一段距离h(h可以0.5mm为一阶)后得出点h,重新过三点作圆,如图(h)所示。 d. 重复步骤3.2.2.2和步骤3.2.2.3,直到满足L1=L2+(0.2~0.8)mm。通过此方法求出产品抽弧形时的外形尺寸 C. 确定抽弧形冲子端部球体半径的方法: a. 以第3.3.2步确定的产品抽弧形时的外形尺寸偏移一个材料厚度。如图(I) b. 以下模入子内孔中半径为r1的两圆弧偏移T*0.6%。如图(I) c. 用三点作圆的方法画出与步骤3.3.3.1和步骤3.3.3.2中确定的三段弧相切的 圆,此圆的半径R就是抽弧形冲子端部球体的半径R(取小数点后一位小数,但标注尺寸时精确到小数点后两位)。如图(J) D. 确定抽弧形冲子身部直径 a. 如果(B)确定的圆球心在产品材料上表面(即上脱板与材料接触面)以上时,圆球与产品材料上平面相交,就得出抽弧形部子身部的断面。如图(K)所示,D9 就是所求的抽弧形冲子身部的直径。 b.如果(B)确定的圆球圆心在产品材料上表面(即上脱板与材料接触面)与下表面 之间,就取抽弧形冲子的身段直径D9等于圆球的直径(即D9=2*R),抽弧形 冲子的端部形状就是一半球体。如图(I) c. 如果(B)确定的圆球圆心在产品材料下表面(即下模板与材料接触面)以下时,必须请主管决定。

算法试题

1 操作系统是算法吗?请说说算法和程序的区别。 答:不是。 算法是满足下述性质的指令序列: (1)输入:有零个或多个外部量作为算法的输入。 (2)输出:算法产生至少一个量作为输出。 (3)确定性:组成算法的每条指令清晰、无歧义。 (4)有限性:算法中每条指令的执行次数有限,执行每条指令的时间也有限 程序是算法用某种程序设计语言的具体实现。程序可以不满足算法的性质(4)即有限性。 2 关于描述时间复杂度的符号O Ωθ,请简要描述它们的含义。 答:O的定义:如果存在正的常数C和自然数N0,使得当N≥N0时有f(N)≤Cg(N),则称函数f(N)当N充分大时上有界,且g(N)是它的一个上界,记为f(N)=O(g(N))。即f(N)的阶不高于g(N)的阶。 Ω的定义:如果存在正的常数C和自然数N0,使得当N≥N0时有f(N)≥Cg(N),则称函数f(N)当N充分大时下有界,且g(N)是它的一个下界,记为f(N)=Ω(g(N))。即f(N)的阶不低于g(N)的阶。 θ的定义:定义f(N)= θ(g(N))当且仅当f(N)=O(g(N))且f(N)= Ω(g(N))。此时称f(N)与g(N)同阶。 3 算法A的运行时间至少是O(n2),这种说法正确吗?为什么? 答:不正确。因为时间复杂度的符号O描述的是函数具有上界,即最多的运行时间是O(n2)。 6、插入排序、合并排序和快速排序这三种算法,哪几种使用了分治策略?请简述之。答:合并排序和快速排序使用了分治的策略。 合并排序:对要排序的数组A[low…high],令mid=[(low+high)/2],用A[mid]把原数组A[low…high]分成两个子数组,然后对两个子数组进行排序,在合并两个已牌子徐的子数组,产生排序数组。 快速排序:对要排序的数组A[low…high],先使用算法SPLIT重新排列元素,使得原先在A[low]中的祝愿占据其正确的位置A[w],并且所有小于或等于A[w]的元素所处的位置为A[low…w-1],而所有大于A[w]的元素所处的位置是A[w+1…high]。在对子数组A[low…w-1]和A[w+1…high]递归地排序,产生整个排序数组。 归并排序要好于插入排序,插入排序要好于冒泡排序。 7、分治法适合求解的问题一般具有那些特征?分治法可分为哪三个主要步骤? 答:适合分治法求解的问题一般具有以下特征: (1)问题的规模缩小到一定程度就可以容易地解决 (2)问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质 (3)基于子问题的解可以合并为原问题的解 (4)问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。 分治法可分为以下三个步骤: 分解(Divide):将原问题分解为子问题 解决(Conquer):求解子问题 合并(Combine):组合子问题的解得到原问题的解。 分治法的基本思想: 分治法的基本思想是将规模较大的问题分解为规模较小的子问题,子问题之间相互独立且与原问题同类。求解子问题,然后将子问题的解合并为原问题的解。 分治法的求解实例:

实验七 最近点对问题的设计与实现

实验七最近点对问题的设计与实现 一、实验目的 1.掌握分治算法的基本原理 2.利用分治策略编程解决最近点对问题 二、实验要求 1.设计算法 2.写出相应程序 3.保存和打印出程序的运行结果,并结合程序进行分析。 三、实验内容 算法思想:用分治法解决最近对问题,很自然的想法就是将集合S分成两个子集S1和S2,每个子集中有n/2个点。然后在每个子集中递归地求其最接近的点对,在求出每个子集的最接近点对后,在合并步中,如果集合S 中最接近的两个点都在子集S1或S2中,则问题很容易解决,如果这两个点分别在S1和S2中,则根据具体情况具体分析。 1、考虑一维情形下的最近点对问题: 设x1, x2, …, xn是x轴上有n个点构成的集合S,最近对问题就是找出集合S中距离最近的点对。 算法思想:用x轴上的某个点m将S划分为两个集合S1和S2,并且S1和S2含有点的个数近似相同。递归地在S1和S2上求出最接近点对 (p1, p2) 和(q1, q2),如果集合S 中的最接近点对都在子集S1或S2中,则d=min{(p1, p2), (q1, q2)}即为所求,如果集合S中的最接近点对分别在S1和S2中,则一定是(p3, q3),其中,p3是子集S1中的最大值,q3是子集S2中的最小值。 例如:(1)输入 -8,-5,-4,1,3,7,输出为1. (2)输入 -8,-5,-2,1,3,7,输出为2. (3)输入 -8,-4,-1,1,4,7,输出为2.

附加题:(有时间可继续完成下面内容) 2、考虑一维情形下的最近点对问题: 设p1=(x1, y1), p2=(x2, y2), …, p n=(x n, y n)是平面上n个点构成的集合S,最近对问题就是找出集合S中距离最近的点对。 算法:

凸包问题

凸包问题 摘要:凸包问题是计算机几何中的一个经典问题,它要求将平面内的点集用最少的凸点将所有的顶点封闭。凸包问题的应用十分广泛,很多最优化问题经过抽象后可以发现它最终是凸包问题模型;它还可以用于人际关系网络的最小化搜索,通过人际关系,可以合理推断出某人的身份,职位等个人特征。目前求取凸包的常用算法有:穷举法,格雷厄姆扫描法(Graham),分治法,蛮力法和Jarris 步进法。其中穷举法与蛮力法都是建立在穷举的算法思想上,它们的时间复杂度比较大,格雷厄姆扫描法采用几何方面的知识,降低了求解过程的时间复杂度。关键词:凸包问题;计算机几何;格雷厄姆扫描法 一、引言 凸包问题的完整描述:令S 是平面上的一个点集,封闭S 中所有顶点的最小凸多边形,称为S 的凸包,表示为CH(S)。如下图一所示,由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包。 图一 凸包问题是计算机几何的一个经典问题,它可以解决很多优化模型,目前目前求取凸包的常用算法有:穷举法,格雷厄姆扫描法(Graham),分治法,蛮力法和Jarris步进法。本文主要讨论穷举法,蛮力法,以及格雷厄姆扫描法,通过算法思想的描述,计算出相应的时间复杂度,比较这几种算法的优劣。

二、穷举法 穷举法的思想很简单直接,它利用凸包性质—如果点集中的两个点的连线属于凸多边形的边,当且仅当点集中其余的点都在这两个点连线的同一侧。 假设点集合S 中有n 个顶点,则这n 个顶点共可以构成(1) 2n n -条边,对于任何一条边来讲,检查其余的n-2 个点的相对于该直线段的正负性。如果它们有相同的正负性,说明该边是凸多边形的边,反之就不属于凸多边形,继续检查。算法流程图如下: 不相同 相同 N Y 图二:算法流程图 上述算法(穷举法)需要执行n(n-1)/2 次,再次检查n-2 个点的正负性,故算法 时间复杂性为2(1)2 n n -∑=3()o n 。显然这并非一个高效的算法凸包问题有许多更加有效的算法可以达到log n n 的渐近时间复杂度。 三、蛮力法 开始 从点集S 中取出两个顶 点u ,v 判断其余的n-2 个点的相对于该直线段的正负性 判断执行次数是否 大于(1)2n n - 把u ,v 加入凸包 结束

蛮力法分治法求最近对

实验题目 设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。 实验目的 (1)进一步掌握递归算法的设计思想以及递归程序的调试技术;(2)理解这样一个观点:分治与递归经常同时应用在算法设计之中。 实验内容(包括代码和对应的执行结果截图) #include #include #include using namespace std; typedef struct Node {//定义一个点的结构,用于表示一个点 int x; int y; }Node; typedef struct NList {//定义一个表示点的集合的结构 Node* data; int count; }NList; typedef struct CloseNode {//用于保存最近两个点以及这两个点之间的距离 Node a; Node b; double space; }CloseNode; int max; void create(NList & L) { cout<<"请输入平面上点的数目:\n"; cin>>max;

L.count=max; L.data = new Node[L.count];//====================动态空间分配 cout<<"输入"<>L.data[i].x>>L.data[i].y; } //求距离平方的函数 double Distinguish2(Node a,Node b) { return ((a.x-b.x)*(a.x-b.x))+((a.y-b.y)*(a.y-b.y)); } //蛮力法求最近对 void BruteForce(const NList & L,CloseNode & cnode,int begin,int end) { for(int i=begin;i<=end;i++) for(int j=i+1;j<=end;j++) { double space = Distinguish2(L.data[i],L.data[j]); if(space

分治法实现快速排序

实验一 实验名称:利用分治法实现快速排序实验时间: 2012年12月成绩:一、实验目的 分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些子问题,然后将各个子问题的解合并得到原问题的解。 本实验的目的是利用分治策略实现快速排序算法。 二、实验内容 快速排序算法是基于分治策略的排序算法。其基本思想是,对于输入的子数组a[p:r],按以下三个步骤进行排序。 (1)分解:以a[p]为基准元素将a[p:r]划分成3段a[p:q-1],a[q]和a[q+1:r],使a[p:q-1]中任何一个元素小于等于a[q],而a[q+1:r]中任何一个元素大于等于a[q]。下标q在划分过程中确定。 (2)递归求解:通过递归调用快速排序算法分别对a[p:q-1]和a[q+1:r]进行排序。 (3)合并:由于对a[p:q-1]和a[q+1:r]的排序是就地进行的,所以在a[p:q-1]和a[q+1:r]都已排好的序后,不需要执行任何计算,a[p:r]就已排好序。基于这个思想,可实现的快速排序算法如下:void QuickSort(int a[],int p,int r)

{ if(px); if(i>=j) break;

最近点对问题

算法分析与设计最近对问题

最近对问题 问题描述: 在二维平面上的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 #include #include #define NUM 1000 typedef struct{ int x;

相关主题
文本预览
相关文档 最新文档