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

合集下载

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。

最接近点对问题教材

最接近点对问题教材

S2中的q3组成,则p3和q3一定在划分平面 L的距离d内。
第二步筛选:考虑P1中任意一点p,它若与
P2中的点q构成最接近点对的候选者,则必 有distance(p,q)<d。满足这个条件的P2 中的点定落在一个d×2d×2d的长方体R中
重要观察结论:P2中任何2个S中的点的距离 都不小于d。由此可以推出长方体R中最多只有 24个S中的点。
分治法解决二维空间最接近点问题
选取一垂直线l:x=m来作为分割直线。其中m为S中各 点x坐标的中位数。由此将S分割为S1和S2。 递归地在S1和S2上找出其最小距离d1和d2,并设 d=min{d1,d2},S中的最接近点对或者是d,或者是某个 {p,q},其中p∈S1且q∈S2。
第一步筛选:如果最近点对由S1中的p3和
4、设P1是S1中距垂直分割线l的距离在dm之 内的所有点组成的集合; { P2是S2中距分割线l的距离在dm之内所有 n=|S|; 点组成的集合; O(n) 将 P1 和 P2 中点依其 y 坐标值排序; if (n < 2) return ; 并设X和Y是相应的已排好序的点列; 1、m=S中各点x间坐标的中位数; 5、通过扫描X以及对于X中每个点检查Y中与 构造S1和S2; 其距离在dm之内的所有点(最多6个)可以完成 O(n) 合并; O(n) //S1={p∈S|x(p)<=m}, 当X中的扫描指针逐次向上移动时,Y中的 S2={p∈S|x(p)>m} 扫描指针可在宽为2dm的区间内移动; 2、d1=cpair2(S1); 设dl是按这种扫描方式找到的点对间的最 2T(n/2 小距离; d2=cpair2(S2); ) 6、d=min(dm,dl); 常数时间 3、dm=min(d1,d2); return d; 常数时间 }

平面最接近点对问题(分治法)

平面最接近点对问题(分治法)

平⾯最接近点对问题(分治法)头⽂件部分:(1)数据结构部分://涉及的数据结构#ifndef DATASET_H#define DATASET_Hstruct point{ //点结构double x, y;};#endif(2)函数声明部分://函数头⽂件//=======================================#ifndef FUNC_H#define FUNC_H#include "dataset.h"double closest_distance(point s[], int low, int high, point rec[]);double Distance(point a, point b);bool comp_x(point a, point b);bool comp_y(point a, point b);#endif源⽂件部分:(1)函数实现部分://求解最近距离的函数实现#include "dataset.h"#include <math.h>#include <algorithm>using namespace std;double Distance(point a, point b) //计算两点距离{return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) - (a.y - b.y));}bool comp_x(point a, point b) //按x升序判别函数{return a.x < b.x;}bool comp_y(point a, point b) //按y升序判别函数{return a.y < b.y;}//函数实现:rec[]存储最接近点对;double closest_distance(point s[], int low, int high, point rec[]){double d1, d2, d3, d;int mid, i, j, index;double x1, y1, x2, y2; //记录最近的点对point *P = new point[high - low + 1];point temp_1[2], temp_2[2], temp_3[2];if (high - low == 1) //两个点时的情况{rec[0].x = s[low].x; rec[0].y = s[low].y;rec[1].x = s[high].x; rec[1].y = s[high].y;return Distance(s[low], s[high]);}if (high - low == 2) //三个点时的情况{d1 = Distance(s[low], s[low + 1]);d2 = Distance(s[low + 1], s[high]);d3 = Distance(s[low], s[high]);if ((d1 <= d2) && (d1 <= d3)) //这⾥在判断三种情况时,第⼆种情况没必要使⽤(d2<d3)&&(d2<d1),相较更繁琐了;{rec[0].x = s[low].x; rec[0].y = s[low].y;rec[1].x = s[low + 1].x; rec[1].y = s[low + 1].y;return d1;}else if (d2 < d3){rec[0].x = s[low + 1].x; rec[0].y = s[low + 1].y;rec[1].x = s[high].x; rec[1].y = s[high].y;return d2;}else{rec[0].x = s[low].x; rec[0].y = s[low].y;rec[1].x = s[high].x; rec[1].y = s[high].y;return d3;}}mid = (low + high) / 2;d1 = closest_distance(s, low, mid, rec);temp_1[0] = rec[0];temp_1[1] = rec[1];d2 = closest_distance(s, mid + 1 ,high, rec);temp_2[0] = rec[0];temp_2[1] = rec[1];if (d1 <= d2){d = d1;rec[0] = temp_1[0];rec[1] = temp_1[1];}else{d = d2;rec[0] = temp_2[0];rec[1] = temp_2[1];}index = 0;for (i = mid; (i >= low) && ((s[mid].x - s[i].x) < d); i--){P[index++] = s[i]; //点集合P1}for (i = mid + 1; (i <= high) && ((s[i].x - s[mid].x) < d); i++){P[index++] = s[i]; //点集合P2}sort(P, P + index, comp_y); //升序排列for (i = 0; i < index; i++){for (j = i + 1; j < index; j++){if ((P[j].y - P[i].y) >= d)break;else{d3 = Distance(P[i], P[j]);if (d3 < d){rec[0].x = P[i].x; rec[0].y = P[i].y;rec[1].x = P[j].x; rec[1].y = P[j].y;d = d3;}}}}delete []P; //注意动态内存的删除⽅式,防⽌内存泄漏return d;}(2)主函数部分://2018_02_24//使⽤分治法求解⼆维平⾯最接近点问题//============================================================= #include <iostream>#include <math.h>#include <algorithm>#include "dataset.h"//数据结构实现放在这个头⽂件中#include "func.h"//函数声明的头⽂件using namespace std;int main(void){point p[10]; //设定点的集合int n;double minDist;cout << "输⼊点的个数:\n";cin >> n;cout << "输⼊点集:(x , y) \n";for (int i = 0; i < n; i++)cin >> p[i].x >> p[i].y;sort(p, p + n, comp_x); //对输⼊的点先进⾏排序point index[2];minDist = closest_distance(p, 0, n - 1, index);cout << "最⼩距离点对为:(" << index[0].x << "," << index[0].y << "),(" << index[1].x << "," << index[1].y << ")"; cout << "最⼩距离为:\n" << minDist;system("pause");return0;}最后,结果如下:。

分治法二(平面最近点对)

分治法二(平面最近点对)

分治法⼆(平⾯最近点对)上篇⽂章介绍了分治法的概念和基本解题步骤,并附加了⼀个例题帮助⼤家了解分治法的基本思想,在这篇⽂章中,我将对分治法的另⼀个经典问题进⾏分析,希望我的⽂章能够将今天的主题解释清楚。

接下来我将⽤三种不同的⽅法求解“平⾯最近点对”问题。

问题描述:在⼀个平⾯上随机分布着 n 个点,现给定 n 个点的坐标,要求给出最近的两个点之间的距离。

⽅法⼀:原始⽅法题⽬要求求出最近的两点之间的距离,先整理⼀下已知的线索:⾸先点的总个数为 n ;其次已知 n 个点的坐标。

掌握了每个点的坐标,就相当于间接地掌握了任意两点之间的距离。

假设两个点为 A : ( x1 , y1 ) , B : ( x2 , y2 ) ,两点间的距离为 distance ,根据平⾯坐标系中的两点间距离公式可得:distance ^ 2 = ( x1 - x2 ) ^ 2 + ( y1 - y2 ) ^ 2,运⽤该公式对每两个点的距离进⾏计算,并不断更新最⼩值 min_distance 。

核⼼代码为:这个⽅法很直观也最容易想到,不过,由以上的两层循环可知,该⽅法的时间复杂度为 o ( n ^ 2 ) ,当 n 的值不断增⼤时,这个⽅法处理起来就显得⼒不从⼼了。

因此我们必须寻找另⼀种更有效的⽅法,或者在此⽅法上进⾏适当的改进。

接下来⼀起了解⼀下第⼆种⽅法--分治法⽅法⼆:分治法为了做到有理有据,正式叙述解法之前,我得再啰嗦⼏句选择分治法的原因,希望不会引起⼤家的反感。

在本问题中,需要求得最近两点之间的距离,整个问题的规模为 n 个点,不妨将这 n 个点⼀分为⼆,就变成两个求解 n /2 个点规模下最近点对的距离问题,如此不断缩⼩规模,当变成两个点的规模下求解最近点对问题时,显⽽易见,即为这两个点的距离,这样随着问题规模的缩⼩解决的难易程度逐渐降低的特征正是可以⽤分治法解答的问题所具备的特征。

接下来,我们按照分治法解题步骤分割--求解--合并分析这个问题。

用分治法解决最近点对问题:python实现

用分治法解决最近点对问题:python实现

⽤分治法解决最近点对问题:python实现 最近点对问题:给定平⾯上n个点,找其中的⼀对点,使得在n个点的所有点对中,该点对的距离最⼩。

需要说明的是理论上最近点对并不⽌⼀对,但是⽆论是寻找全部还是仅寻找其中之⼀,其原理没有区别,仅需略作改造即可。

本⽂提供的算法仅寻找其中⼀对。

解决最近点对问题最简单的⽅法就是穷举法,这样时间复杂度是平⽅级,可以说是最坏的策略。

如果使⽤分治法,其时间复杂度就是线性对数级,这样⼤⼤提⾼了效率。

⾸先⽤分治法解决该问题的基本思路可以参考 /lishuhuakai/article/details/9133961 ,说的很详细,但⼤致思路就是先根据x轴把所有点平分,然后分别在每⼀部分寻找最近点对,最后通过⽐较选⼀个最⼩的。

当然其中最核⼼的地⽅是跨域求距离,原⽂写的很清楚,在此就不再赘述了。

以下是代码:from math import sqrtdef nearest_dot(s):len = s.__len__()left = s[0:len/2]right = s[len/2:]mid_x = (left[-1][0]+right[0][0])/2.0if left.__len__() > 2: lmin = nearest_dot(left) #左侧部分最近点对else: lmin = leftif right.__len__() > 2: rmin = nearest_dot(right) #右侧部分最近点对else: rmin = rightif lmin.__len__() >1: dis_l = get_distance(lmin)else: dis_l = float("inf")if rmin.__len__() >1: dis_2 = get_distance(rmin)else: dis_2 = float("inf")d = min(dis_l, dis_2) #最近点对距离mid_min=[]for i in left:if mid_x-i[0]<=d : #如果左侧部分与中间线的距离<=dfor j in right:if abs(i[0]-j[0])<=d and abs(i[1]-j[1])<=d: #如果右侧部分点在i点的(d,2d)之间if get_distance((i,j))<=d: mid_min.append([i,j]) #ij两点的间距若⼩于d则加⼊队列if mid_min:dic=[]for i in mid_min:dic.append({get_distance(i):i})dic.sort(key=lambda x: x.keys())return (dic[0].values())[0]elif dis_l>dis_2:return rminelse:return lmin# 求点对的距离def get_distance(min):return sqrt((min[0][0]-min[1][0])**2 + (min[0][1]-min[1][1])**2)def divide_conquer(s):s.sort(cmp = lambda x,y : cmp(x[0], y[0])) nearest_dots = nearest_dot(s)print nearest_dots测试⼀下,⽐如说要找这些点中最近的⼀对s=[(0,1),(3,2),(4,3),(5,1),(1,2),(2,1),(6,2),(7,2),(8,3),(4,5),(9,0),(6,4)]运⾏⼀下divide_conquer(s),最终打印出[(6, 2), (7, 2)],Bingo。

平面最近点对问题(分治)

平面最近点对问题(分治)

平⾯最近点对问题(分治)平⾯最近点对问题是指:在给出的同⼀个平⾯内的所有点的坐标,然后找出这些点中最近的两个点的距离.⽅法1:穷举1)算法描述:已知集合S中有n个点,⼀共可以组成n(n-1)/2对点对,蛮⼒法就是对这n(n-1)/2对点对逐对进⾏距离计算,通过循环求得点集中的最近点对2)算法时间复杂度:算法⼀共要执⾏ n(n-1)/2次循环,因此算法复杂度为O(n2)代码实现:利⽤两个for循环可实现所有点的配对,每次配对算出距离然后更新最短距离.for (i=0 ; i < n ;i ++){for(j= i+1 ; j<n ;j ++){点i与点j的配对}}⽅法2:分治1) 把它分成两个或多个更⼩的问题;2) 分别解决每个⼩问题;3) 把各⼩问题的解答组合起来,即可得到原问题的解答。

⼩问题通常与原问题相似,可以递归地使⽤分⽽治之策略来解决。

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

平面最近点对问题

平面最近点对问题

平⾯最近点对问题平⾯最近点对问题正如其名,给定平⾯上的n个点,找出其中的⼀对点,使得这对点的距离在所有点对中最⼩。

⾸先显⽽易见地我们可以得到这个问题的O(n^2)算法,枚举所有点对即可。

但是很显然我们可以注意到,这⾥⾯有很多点对显然不是最优的,那么我们可以想到⼀种剪枝⽅法,就是将只对x坐标差值⼩于当前已知最⼩值的点对进⾏判断(否则必然不是最优解),从⽽减少判断量。

我们考虑使⽤分治来实现这种剪枝,先将平⾯上的点分为两部分,分治求出两部分内部的最近点对距离。

之后我们要做的就是枚举两个集合之间的点对,并与两部分内部的最近点对距离⽐较来得到最近点对距离。

这⾥我们是不需要枚举所有点对的,因为我们已经得到了⼀个两部分各⾃内部最⼩的点对距离,因⽽我们可以结合上⾯的根据x坐标的剪枝⽅法,只枚举分别属于两部分的x坐标差⼩于已知最⼩距离的点对。

这样做的复杂度近似于O(n\log^2n),⾄于怎么得到的……我也不知道。

_(:зゝ∠)_例题:1. Vijos 1012 清帝之惑之雍正链接:2. 平⾯最近点对(加强版)链接:另外附上模板:注意,本模板保留六位⼩数,不能直接⽤于提交上⾯的例题,若要提交请修改输出精度。

1 #include <iostream>2 #include <cstdlib>3 #include <cstdio>4 #include <cstring>5 #include <string>6 #include <sstream>7 #include <cctype>8 #include <cmath>9 #include <algorithm>10#define THE_BEST_PONY "Rainbow Dash"1112using namespace std;13const int maxn=220000,INF=~0u>>1;1415struct Point{16double x,y;17bool operator < (const Point &a) const {18if(x<a.x) return true;19if(x>a.x) return false;20return y<a.y;21 }22 }p[maxn];2324int n;25double ans;2627double DisP(int a,int b){28return sqrt((p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y));29 }3031double GetAns(int l,int r){32int mid=(l+r)>>1;33if(l==r) return INF;34if(l==r-1) return DisP(l,r);35double len=min(GetAns(l,mid),GetAns(mid+1,r));36for(int i=mid;i>=l;i--){37if(p[i].x+len<p[mid].x) break;38for(int j=mid+1;j<=r;j++){39if(p[mid].x+len<p[j].x) break;40 len=min(len,DisP(i,j));41 }42 }43return len;44 }4546int main(){47 scanf("%d",&n);48for(int i=0;i<n;i++)49 scanf("%lf%lf",&p[i].x,&p[i].y);50 sort(p,p+n);51 ans=GetAns(0,n-1);52 printf("%.6lf",ans);53return0;54 }Processing math: 0%。

用蛮力法和分治法解决最近对问题

用蛮力法和分治法解决最近对问题

算法分析与复杂型设计作业学院计算机与控制工程学院专业计算机软件与理论班级 Y130701 学生姓名郑晓璐流水号 201307892014年4月问题:设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。

蛮力算法描述:int ClosestPoints(int n, int x[ ], int y[ ]){minDist=Double.POSITIVE_INFINITY;;for (i=1; i< n; i++)for (j=i+1; j<=n; j++){d=(x[i]-x[j])* (x[i]-x[j])+(y[i]-y[j])* (y[i]-y[j]);if (d< minDist) {minDist=d;index1=i;index2=j;}}return minDist;}程序:import java.util.*;public class ClosestPair1{public static void main(String[] args){/***输入需要比较的点的对数存在变量n中*/Scanner in=new Scanner(System.in);System.out.println("How many pairs of points to compare?(有多少对点需要比较?)");int n=in.nextInt();int[] x=new int[n];int[] y=new int[n];/***输入这些点的横坐标和纵坐标分别存储在x[n]和y[n]*/System.out.println("Please enter these points,X-coordinate(请输入这些点,横坐标):");for(int i=0;i< n;i++){x[i]=in.nextInt();}System.out.println("Please enter these points,Y-coordinate(请输入这些点,纵坐标):");for(int i=0;i< n;i++){y[i]=in.nextInt();}double minDist=Double.POSITIVE_INFINITY;double d;int indexI=0;int indexJ=0;/***求解最近对距离存于minDist中*/double startTime=System.currentTimeMillis();//startTimefor(int i=0;i< n-1;i++){for(int j=i+1;j< n;j++){d=Math.sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));if(d< minDist){minDist=d;indexI=i;indexJ=j;}}}double endTime=System.currentTimeMillis();//endTime/***打印输出最后求出的结果,最近的是哪两个点,以及最近距离和程序用的时间*/System.out.println("The closest pair is:("+x[indexI]+","+y[indexI]+") and ("+x[indexJ]+","+y[indexJ]+")");System.out.println("The closest distance is "+minDist);System.out.println("Basic Statements take(基本语句用时)"+(endTime-startTime)+" milliseconds!");}}运行:分治算法描述:可以划一条垂线,把点集分成两半:PL和PR。

分治法解决空间最接近点对问题

分治法解决空间最接近点对问题

第一作者简介 : 筱魁(90 , , 李 18 一)男 吉林省四平市人 , 为吉林师 范大学研究生部助教 , 现 硕士 . 研究方 向: 计算机视觉及 图形图像 .
论 最关 键 的问题 是 如 何 实 现分 治 法 中的合 并 步骤 ,
即由 . 和 . 的最接近点对 , s l s 2 如何求得原集合 . 中 s 的最 接近点 对 , 因为 J 和 J s 1 s 2的最 接 近点对 未 必 就 提法为 : 给定 平 面上 n个点 , 找其 中的 一对 点 , 得 使 是 . s的最接 近点对 . 如果 组 成 . s的最 接 近 点对 的 2 在 n 个点 的所 有点 对 中 , 该点 对 的距离 最小 ( 格 地 严 个 点 都在 . 中或都在 . 中 , s 1 s 2 只需 比较 一 次 即可 确 说, 最接 近点 对可 能 多于 一对 . 了简 单起 见 , 里 为 这 定; 但是 , 如果 这 2个点 分别 在 s 和 s 。 2中, 对 于 则 只限于找其 中的一对)朴素的解法只要将每一点与 . . 中任 一点 P, 2 s , S 中最 多只有 n 2 点 与它构成 最 /个 其 他 n一1 个点 的距 离算 出 , 出达 到最 小距离 的两 找 接近点对的候选者 , 仍需做 n/ 次计算和比较才能 4 个点即可 . 然而, 这样做效率太低 , 需要 0 n ) ( 的计 确定 .的最接近点对 , s 合并步骤耗时为 0 n )可 ( . 算 时间 , 分 治法可 以得 到 0( lg ) 用 no n 的算 法 l . 2 三 J 以看 出 , 并 步骤耗 时太 多 , 合 我们应 在合并 算法 上进 维 空间 中的最 接近点 对 问题 , 如 , 例 在空 中交通 控制 行 改进 . 我们 用 ( ) 示 P点 的 坐标 值 . P 表 首先 递 问题 中, 将飞 机作 为空间 中移 动 的一个 点来看 待 , 若 归地 在 . 和 . 上 解最 接 近点对 问题 , s l s 2 我们 分 别 得 则在任 一 时刻具 有 最大 碰撞 危 险 的二 架 飞 机 , 是 就 到 . s 1和 . s 2中 的 最 小 距 离 1 和 2 设 = .现 这个空 间 中最接 近 的一 对 点 , 其 求 解 的相 关 文 献 对 mn l )若 S的最接 近点对 ( q i( , . 2 P, )之 间的距 离 非常少 , 本文把用分治法解决平 面最接近点对问题 d q P)< , P和 q必分 属 于 . 和 . . (, 则 s l s 不妨设 P 2 推广 到三维 空 间 中. ∈S, lq∈ S , 么 , 2那 P和q 平面 Z 距 的距 离均小 于 . 2 算法实现 因此 , 我们 若用 P1 P2 别 表示平 面 Z 后 的宽 和 分 前 为 的 2 区域 ( . 个 P 为平 面 = / 与平 面 = / + / 7 , / 7 , 空 间最接 近点 对问题 描 述 : 定 含 有 n个 空 间 给 P2 / 7 , 点 的集 合 ., 出其 中一对点 , 得在 由这 n个 点 构 之 间所 夹的 区域 , 为平 面 = / 与平 面 = n s找 使

平面点集最近邻问题的解决方法

平面点集最近邻问题的解决方法

平面点集最近邻问题的解决方法在计算几何中,最近邻问题是一类比较基础的问题。

在平面上,给定一些点,我们需要找到每个点的最近的邻居点。

这个问题有很多应用,在计算机图形学,GIS,机器学习等领域都有广泛的应用。

本篇文章将介绍平面点集最近邻问题的解决方法。

1. 暴力求解最简单的解决方法就是对于每一个点,求出它和其他点的距离,并找到最近的邻居点。

这个方法被称为暴力求解。

显然,暴力求解的时间复杂度是$O(n^2)$。

当$n$很小时,暴力求解是可行的,但当$n$比较大时,算法的效率会非常低。

2. 分治法分治法是一种递归的思想,将一个大问题划分成若干个小问题进行求解,最后再将这些小问题的解合并起来,得到整体的解。

对于平面点集最近邻问题,分治法的思想可以被应用到二维平面的划分上。

我们可以将平面分成若干个小的正方形区域。

然后对于每个区域,求出区域内的点之间的最近邻关系。

接下来,对于每个点,我们需要找到它所在的区域,并在相应的区域内查找最近邻点。

如果我们选择的合适的区域大小,可以使得算法的时间复杂度在平均意义下为$O(n \log n)$,但最坏情况下的时间复杂度仍为$O(n^2)$。

3. K-D树对于平面点集最近邻问题,K-D树是一种非常有效的解决方法。

K-D树是一种二叉树结构。

对于K-D树的每个节点,我们选取一个维度,并根据该维度选择一个中值。

然后,将这个维度小于中值的点放在左子树中,将大于中值的点放在右子树中。

接下来,我们递归地构建左右子树,直到节点中只有一个点为止。

构建完成后,我们可以使用深度优先搜索遍历K-D树,找到每个点的最近邻点。

与分治法类似,K-D树也可以被看作是将平面点集划分成若干个小的区域。

每个节点都代表了一个区域,区域中的点可以被分为两个部分。

根据节点代表的维度和中值,我们可以决定要查找哪棵子树。

K-D树的构建时间复杂度为$O(n \log n)$,每次查询的时间复杂度为$O(\log n)$。

实验一:用分治法解最接近点对问题

实验一:用分治法解最接近点对问题

实验报告
课程名称:算法设计与分析
实验项目:实验一:用分治法解最接近点对问题
指导教师:虞勤国
实验位置:计算机中心二楼
姓名:
班级:计科
学号:
日期:
一、实验目的
通过上机实验,要求掌握分治法的问题描述、算法设计思想、程序设计和算法复杂性分析等。

二、实验环境
1、装有Visual C++6.0或Visual Studio 2005的计算机。

2、本次实验共计3学时。

三、实验内容
1、熟悉分治算法思想
掌握如何创建应用程序。

掌握对最接近点对问题描述,及如何运用算法策略对问题解决和实现。

2、掌握如何编译程序
理解编译过程中的错误信息,并掌握如何排错。

3、掌握如何调试程序
掌握如何通过设置断点来单步调试程序,如何查看当前变量的值。

4、实验题:
完成用分治法解最接近点对问题的实验。

5、要求:
实现该实验结果。

通过该实验题,解决最接近点对问题。

(1)程序设计(程序清单及说明)
(2)数据输入和结果输出
(3)算法复杂性分析
四、实验心得与小结
五、指导教师成绩评定:。

平面最近点问题

平面最近点问题

平面最近点问题1.上机要求:使用Divide & Conquer 解决问题。

2.解决问题思想:利用分治的算法,将大问题划分为几个同样的小问题来解决。

3. 要求:题目:平面上有2n个不同点P1,P2,P3 (2)对所有1≤ i ≤2n,有P i.X<P i+1.X输入:n (整数, n>0 且n<10)(随机产生2n个不同点,其中1<=x,y<=10 )输出:距离最近的两个点的坐标和距离。

4.开发工具:Delphi7.0(选择的原因,开发时间短,且考虑界面等要求,还有熟悉程度。

)5.算法描述:利用分治法解决该问题的步骤如下:1,随机生成2n个不同点,并把这2n 不同的点,用一个数组存起来,并用快速排序的方法排对它们按X坐标和Y坐标进行排序(在本程序中,使用知对下标排序的方法)也就是有一个存放点集的数组不变,其X和Y中存放的是根据下标排好的点集的下标。

2,由于我们已经把点集根据X坐标排好了序,所以我们可以以2n-1为中线将产生的随机点集合的分成A部分P1,P2,P3······P2n-1,和B部分P2n-1,P2n-1+1,P2n-1+2·····P2n B部分中分别寻找最近的两点。

分别把最短距离存放在d1和d2中,接着比较在两部分本别得到的最短距离,将较小的值放入d1中。

(对A部分和B部分,我们采用的是把点集以X轴为标准,以Y轴下标,分别把点集存入YL,YH中,YL,YH是在分割中的局部数组。

也即A部分放在YL,B部分放在YH中。

这样保证YL和YH是递增的。

3,还有我们再找到点分别在A和B部分点集的距离,以P[2n-1]点的为基准,从A和B两部分钟与P[2n-1]的坐标的差若小于*2d则将该点存入YL数组中,接着对返回的距离比较小的部分的点位基准,只要比较另一个数组中的七个点集可,在把它们中的较小值存入d1,存入两个点的坐标,最后分治函数返回。

最接近点对问题_分治法

最接近点对问题_分治法

最接近点对问题_分治法⼀、问题描述给定平⾯上的n个点,找其中的⼀对点,使得在n个点组成的所有点对中该点对间的距离最⼩。

⼆、解题思路及所选算法策略的可⾏性分析思路:利⽤分治法来解决问题。

递归⼦结构求最接近点对总体可分为⼏个步骤:1、当问题规模⼩于20,直接求解最⼩点对2、将n个点组成的集合S分成2个⼦集S1和S23、递归求出两个⼦集中的最接近点对并⽐较出最⼩点对,记录距离dmin4、以X坐标为基准找到所有点中线,在中线附近找出相距可能⼩于dmin的点对点,记录于S3和S45、求S3和S4每点对距离,和dmin进⾏⽐较,求解最接近点对策略可⾏性分析:设直线l上有2m个点,以m为中点将l分割成两条线段dl,dr,然后求出dl和dr这两点条线段中的最⼩点距d1,d2,此时d=min{d1,d2},再通过计算出dl线段的中最⼤点与dr线段中的最⼩点之间的距离D,最⼩距离则为min{d,D}.⼆维情况与此相似,最⼤的区别只是对于中线位置的点,⼆维情况只是针对中线旁好多可能点,再在Y轴⽅向上进⾏点的筛选,以减少平⽅计算次数。

三、伪代码描述及复杂度分析Public static double closestPoint(S){1、⾸先,递归结束条件,当数组长度在⼀定范围内时直接求出最近点,蛮⼒求解2、求所有点在X坐标中的中位数midX3、以midX为界将所有点分成两组分别存放在两个表中4、将两张表转化为数组类型,并分别按X坐标升序排列5、求S1中的最近距离的两个点6、求S2中的最近距离的两个点7、求两最近距离的最⼩值8、在S1、S2中收集距离中线⼩于d1的点,分别存放于两个表中9、分别将表T3、T4转换为数组类型的S3、S4,并将其分别按Y坐标升序排列10、求解S3、S4两者之间可能的更近(相⽐于d1)距离 , 以及构成该距离的点}复杂度分析:设算法耗时T(n)。

算法第1步、第2步、第3步和第8步⽤了O(n)时间。

分治算法之平面最接近点问题

分治算法之平面最接近点问题

分治算法的应用课程名称:算法设计与分析院系:计算机科学与信息工程学院学生姓名:*******学号:************专业班级:***************************** 指导教师:******2013年12月27日分治算法的应用摘要:分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。

如果分解得到的子问题相对来说还太大,则可反复使用分治法策略将这些子问题分成更小的同类型子问题,必要时逐步合并这些子问题的和,最终就可得到原问题的解。

有分治法的基本思想我们了解到,分治法求解很自然的可以利用一个递归过程来表示,可以这样说分治法就是一种找大规模问题与小规模问题的关系,是递归设计方法的一种具体策略。

分治法与动态规划法实际上都是递归思想的运用,二者的根本策略都是对问题进行分解,找到大规模与小规模的关系,然后通过解小规模的解,得出大规模的解,不同点:适用于分治法的问题分解成子问题后,各子问题间无公共子问题,而动态规划法相反。

大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。

这种使子问题规模大致相等的做法是出自一种平衡(balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好。

子问题规模大致相同、平衡,这样最有效,通常k = 2 ,从分治法的一般设计模式可以看出,用它设计出的程序一般是一个递归过程。

因此,分治法的计算效率通常可以用递归方程来进行分析。

关键词:分治法平面最接近点二分法递归子问题目录第1章绪论 (3)1.1 分治算法的知识介绍 (3)1.2 分治算法的问题描述 (3)第2章分治算法的理论知识 (5)2.1数据结构和算法效率 (5)2.2分治算法之折半查找 (5)第3章平面最接近点问题 (6)3.1 平面最接近点问题描述 (6)3.2 平面最接近点问题算法分析 (7)3.3 测试结果与分析 (9)第4章结论 (11)参考文献 (12)第1章绪论1.1 分治算法的知识介绍分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。

分治 最近点对 证明过程

分治 最近点对 证明过程

分治最近点对证明过程分治算法是一种将问题分解为更小的子问题,并通过递归解决子问题,最后将子问题的解合并起来得到原问题解的方法。

最近点对问题是指在一个给定的点集中,找到距离最近的两个点的问题。

在本文中,我们将使用分治算法来解决最近点对问题,并对其正确性进行证明。

我们需要明确最近点对问题的定义。

给定一个点集P,我们需要找到其中两个点p和q,使得它们的距离d(p,q)最小。

距离可以使用欧氏距离或其他度量方式来定义。

我们的目标是设计一个高效的算法来解决这个问题。

分治算法的基本思想是将问题分解为更小的子问题,并通过递归解决子问题。

在最近点对问题中,我们可以将点集P划分为两个较小的子集P1和P2,分别包含点集P的前一半和后一半的点。

然后,我们分别在P1和P2中递归地找到最近点对。

假设在P1和P2中分别找到的最近点对是(p1,q1)和(p2,q2)。

接下来,我们需要考虑P1和P2之间的最近点对。

我们可以观察到,P1和P2中的点到分割线的距离不能超过d1和d2,其中d1和d2分别是P1和P2中找到的最近点对的距离。

因此,我们只需要考虑距离分割线小于d的点。

我们可以将P1和P2按照x轴坐标排序,并找到中间点mid。

然后,我们可以构建一个矩形区域,将其划分为两个部分,分别包含P1和P2的点。

我们只需要在这个矩形区域中找到距离分割线小于d 的点对。

在这个矩形区域中,我们可以按照y轴坐标排序点,并使用滑动窗口的方法来找到距离最近的点对。

具体来说,我们可以从矩形区域的顶部开始,依次考虑每个点,并计算它与后面d/d2个点的距离。

如果找到了距离更小的点对,则更新最近点对的距离。

我们将在P1、P2和跨越分割线的点中找到最近的点对,并返回其距离。

通过以上步骤,我们可以使用分治算法来解决最近点对问题。

接下来,我们将证明该算法的正确性。

我们可以观察到,如果两个点p和q是最近点对,并且它们在分割线的同一侧,那么它们必定在P1或P2中。

最近点对问题

最近点对问题

算法分析与设计最近对问题最近对问题问题描述:在二维平面上的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、问题描述:给定n个点(xi,yi) 1<=i<=n,找出其中距离最近的两个点。

分析:采用分而治之设计技术,将平面上的n个点的集合S分成2个子集S1和S2,每个子集中约有n/2个点,然后在每个子集中递归地求其最接近点。

于是,原问题变为:(1)求S1中最近距离的两个点;(2)求S2中最近距离的两个点;(3)由(1)、(2)得到S中的最接近点。

有一个关键:如何实现组合解?(1)如果组成S中的最近距离点都在S1中,或都在S2中,则问题很容易解决!(2)如果组成S中的最近距离点分别在S1和S2中,那么,如何组合解?由鸽舍原理对于P1中任一点p,P2中最多只有6个点与它构成最近点的侯选者,于是组合解只需要检查6*(n/2)=3n对侯选点而不是n(2)/4个。

将p和P2中的所有S2的点投影到垂直线l上,由于能与p点构成侯选点的点都在矩形R中,所以它们在直线l上的投影点距p在l上的投影点的距离都小于最近距离。

从上面的分析知,这种点只有6个。

因此,若将P1和P2中的所有点按其y坐标排好序,则对P1中的所有点,对排好序的所有点作一次扫描,就可以找出所有最接近点对的侯选者,对P1中的每一点最多只要检查P2中排好序的相继的6个点。

2、基本算法:Public static double cpair2(S){如果点的个数n小于2,则显示提示信息:只有一个点不能求距离,终止算法;1.m=S中各点x坐标的中位数;(S为点的集合) 构造S1和S2;//S1={p∈S|x(p)<=m}, S2={p∈S|x(p)>m}2. d1=cpair2(S1); d2=cpair2(S2);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 d;}3、实现环境和运行平台:采用java编写程序,jdk4.0编译调试,使用jdk的appletviewer显示运行结果。

算法实验四分治法实验报告

算法实验四分治法实验报告

算法实验四分治法实验实验一最近点对最近点对问题描述:对平面上给定的N个点,给出所有点对的最短距离即,输入是平面上的N个点,输出是N点中具有最短距离的两点要求随机生成N个点的平面坐标,应用穷举法编程计算出所有点对的最短距离要求随机生成N个点的平面坐标,应用分治法编程计算出所有点对的最短距离。

二、实验数据及分析平面点数为100:平面点数为500平面点数为1000:可以看出,分治法的运行效率要明显比直接法要高。

三、核心代码#include"stdafx.h"#include"Point.h"#include<cstdlib>#include<time.h>#include<iostream>#include<algorithm>#include<cmath>#define M 500using namespace std;double start,stop,t;Point p[(M)];Point p0;//存直接法的点的Point p1;//存直接法的点的Point p3;//存分治法的点的Point p4;//存分治法的点的bool comp(Point p1,Point p2){if(p1.x != p2.x) return p1.x < p2.x;else return p1.y < p2.y;}/******分治法模块******/double dist(Point p1, Point p2){return sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y)); }double getMIN(double a, double b){ return a<b?a:b;}double search(int f,int r){if(f == r)return 0;if(f == r - 1){return dist(p[f],p[r]);}if(f == r - 2)returngetMIN(getMIN(dist(p[f],p[f+1]),dist(p[f+1],p[f+2])),dist(p[f],p[f+2] ));int mid = (f+r) >> 1;//右移正好除以double nowMIN = getMIN(search(f,mid),search(mid+1,r));for(int i=f;i<=r;i++)for(int j=i+1;j<=i+5 && j<=r;j++){double t=dist(p[i],p[j]);if(nowMIN>=t){nowMIN=t;p3=p[i];p4=p[j];}}return nowMIN;}int _tmain(int argc, _TCHAR* argv[]){ srand((unsigned int )time(0));for(int i=0;i<(M);i++){p[i].x=rand()%(M)+rand()%100;p[i].y=rand()%(M)+rand()%1000;}cout<<"将随机序列进行初步排序后:";sort(p,p+(M),comp);for(int i=0;i<(M);i++){cout<<"("<<p[i].x<<","<<p[i].y<<")"<<" ";}cout<<endl;cout<<endl;/******直接法模块******/start=clock();int k=0;int f=(M)-1;double flag=sqrt((p[0].x - p[1].x)*(p[0].x - p[1].x) + (p[0].y -p[1].y)*(p[0].y - p[1].y));double a=0;do{ for(int j=k+1;j<=((M)-1);j++){//j表示现在和哪个在比较a=sqrt((p[k].x - p[j].x)*(p[k].x - p[j].x) + (p[k].y - p[j].y)*(p[k].y - p[j].y));if(a<=flag){flag=a;p0=p[k];p1=p[j];}}k++;//k是说当前的基准点是第几个}while(--f);//进行M-1次循环cout<<endl;cout<<endl;cout<<"直接法最短距离为:"<<flag<<endl;cout<<"这两点分别为: "<<"("<<p0.x<<","<<p0.y<<") ,("<<p1.x<<","<<p1.y<<")"<<endl;stop=clock();t=(stop-start)/CLK_TCK*1000;cout<<"直接法运行时间:"<<t<<endl;cout<<endl;cout<<endl;start=clock();double result = search(0,(M)-1);//分治法函数cout<<"分治法最短距离:"<<result<<endl;cout<<"这两点分别为: "<<"("<<p3.x<<","<<p3.y<<") ,("<<p4.x<<","<<p4.y<<")"<<endl;stop=clock();t=(stop-start)/CLK_TCK*1000;cout<<"分治法运行时间:"<<t<<endl;return 0;}。

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

一. 用分治算法解平面最接近点对问题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++程序语言有了更进一步的认识。

相关文档
最新文档