分治法最近点对

分治法

分治法将一个难以直接解决的大问题划分成一些规模较小的子问题,分别求解各个子问题,再合并子问题的解得到原问题的解。

一般来说,分治法的求解过程由以下三个阶段组成:

  1. 划分:把规模为n的原问题划分为k个规模较小的子问题。
  2. 求解子问题:各个子问题的解法与原问题的解法通常是相同的,可以用递归的方法求解各个子问题,有时递归也可以用循环来实现。
  3. 合并:把各个子问题的解合并起来,合并的代价因情况不同有很大的差异,分治算法的效率很大程度上依赖于合并的实现。

最近点对问题

问题描述

设p1=(x1,y1),p2=(x2,y2),···,pn=(xn,yn)是平面上n个点构成的集合S,最近点对问题就是找出集合S中距离最近的点对。严格地说,最接近的点对可能多于一个,简单起见,找出一个即可。

应用实例

假设在一个金属片上钻n个大小一样的洞,如果洞的距离太近,金属就可能会断裂。可以通过任意两个洞的最小距离来估算金属断裂的概率。这种最小距离问题实际上也就是最近点对问题。

想法

最近点对的分治策略如下:

(1)划分:将集合S分成两个子集S1和S2根据平衡子问题原则,每个子集中大约有n/2个点,设集合S的最近对是pi和pj,则会出现以下三种情况:

  1. pi∈S1,pj∈S1,即最近对均在集合S1中;
  2. pi∈S2,pj∈S2,即最近对均在集合S2中;
  3. pi∈S1,pj∈S2,即最近对分别在集合S1和S2中。

(2)求解子问题:对于划分阶段的情况1和情况2可递归求解,如果最近对分别在两个子集中,在后边做讨论。

(3)合并:比较在划分阶段三种情况下的最近点对,取三者之中距离较小者为原问题的解。

下面讨论划分阶段的情况3:

为了将平面上的点集S分割为点的个数大致相同的两个集合,选取垂直线x=m来作分割线,其中m为S中各点x坐标的中位数。由此将S分割为S1和S2。递归地在S1和S2中求解最近对问题,分别得到S1中的最近距离d1和S2中的最近距离d2,令d=min(d1,d2。若S的最近对(p,q)之间的距离小于d,则p和q必定分属于集合S1和S2。那么,不妨设p∈S1,q∈S2,则p和q距离直线x=m的距离均小于d,所以,可以将求解限制在以x=m为中心,宽为2d的垂直带P1和P2中,垂直带之外的任何点对之间的距离都一定大于d。


假设点p(x,y)是集合P1和P2中y坐标最小的点,则点p可能在P1中也可能在P2中,现在需要找出来和点p之间小于d的点,显然这样的点的y坐标一定位于区间[y,y+d]之间,而且这样的点不会超过8个,因为P1和P2中点的相互之间的距离至少为d,如下图所示。


所以,可以将P1和P2中的点按照y坐标升序排列,顺序地处理P1和P2中的点p(x,y),在y坐标区间[y,y+d]内最多取出8个候选点,计算它们和点p之间的距离。

算法

简单起见,假设点集S已按照x坐标升序排列,伪代码描述如下:

输入:按x坐标升序排列的n个点的集合S
输出:最近点对的距离

  1. 如果n等于2,则返回(x1,y1)和(x2,y2)之间的距离,算法结束;
  2. 划分:m=S中各点x坐标的中位数;
  3. d1=计算{(x1,y1),···,(xm,ym)}的最近对距离;
  4. d2=计算{(xm,ym),···,(xn,yn)}的最近对距离;
  5. d=min{d1,d2};
  6. 依次考察集合S中的点p(x,y),如果x<=xm并且x>=xm-d,则将点p放入集合P1中;如果x>xm并且x<=xm+d,则将点p放入集合P2中;
  7. 将集合P1和P2按y坐标升序排列;
  8. 对集合P1和P2中的每个点p(x,y),在y坐标区间[y,y+d]内最多取出8个候选点,计算与点p的最近距离d3
  9. 返回min{d,d3};

源代码

#include<iostream>
#include<math.h>
#include<stdlib.h>using namespace std;int M[2], N[2], P[2], Q[2];typedef struct point
{double x,y;
}point;void Qsortx(point *A, int low, int high){double tempx, tempy;int i = low, j = high;if(low < high){tempx = A[i].x;tempy = A[i].y;while(i != j){while(j > i && A[j].x > tempx)j--;if(i < j){A[i].x = A[j].x;A[i].y = A[j].y;i++;}while(i < j && A[i].x < tempx)i++;if(i<j){A[j].x = A[i].x;A[j].y = A[i].y;j--;}A[i].x = tempx;A[i].y = tempy;Qsortx(A,low,i-1);Qsortx(A,i+1,high);}}}
void Qsorty(point *A, int low, int high){double tempx, tempy;int i = low, j = high;if(low < high){tempx = A[i].x;tempy = A[i].y;while(i != j){while(j > i && A[j].y > tempy)j--;if(i<j){A[i].x = A[j].x;A[i].y = A[j].y;i++;}while(i < j && A[i].y < tempy)i++;if(i < j){A[j].x = A[i].x;A[j].y = A[i].y;j--;}A[i].x = tempx;A[i].y = tempy;Qsorty(A,low,i-1);Qsorty(A,i+1,high);}}}double d(point p1, point p2){double dx, dy, dm;dx = p1.x - p2.x;dy = p1.y - p2.y;dm = pow(dx,2) + pow(dy,2);return sqrt(dm);}void printarry(point *points, int n){for(int i=0; i < n; i++){cout<<"("<<points[i].x<<","<<points[i].y<<")";}cout<<endl;cout<<endl;}double cp(point *S,point *Y,int low,int high){int e, r, mid, k = 0, n=high-low+1;double x0, min, minl, minr, minlr;point T[n];mid = (low + high) / 2;x0 = S[mid].x;if(n == 2){return d(S[low], S[high]);M[0] = low;M[1] = high;}if(n == 3){double d1, d2, d3;d1 = d(S[low], S[low+1]);d2 = d(S[low], S[low+2]);d3 = d(S[low+1], S[low+2]);if(d1<=d2){min = d1;M[0] = low;M[1] = low+1;}else{min = d2;M[0] = low;M[1] = low+2;}if(min > d3){min = d3;M[0] = low + 1;M[1] = low + 2;}}else{minl = cp(S, Y, low, mid);N[0] = M[0];N[1] = M[1];minr = cp(S, Y, mid+1, high);P[0] = M[0];P[1] = M[1];if(minl <= minr){min = minl;Q[0] = N[0];Q[1] = N[1];}else{min = minr;Q[0] = P[0];Q[1] = P[1];}for(int i = 0; i < n; i++){if(fabs(Y[i].x-x0) <= min){T[k].x = Y[i].x;T[k].y = Y[i].y;k++;}}minlr = 2*min;for(int i=0;i<k;i++){int jj;if((i+7) < k)jj=i+7;else jj = k;for(int j = i+1; j < jj; j++){double dd = d(T[i], T[j]);if(dd<minlr){minlr = dd;e = i;r = j;}}}if(minlr < min){min = minlr;for(int i = 0; i < n; i++){if(T[e].x == S[i].x && T[e].y == S[i].y)Q[0] = i;}for(int j = 0; j < n; j++){if(T[r].x == S[j].x && T[r].y == S[j].y)Q[1] = j;}}}return min;}int main(){int n;int f = 1;double mini;cout<<"请输入点的个数:"<<endl;while(f){cin>>n;if(n <= 3)cout<<"非法输入!请重新输入:"<<endl;else{f = 0;break;}}point S[n], Y[n];cout<<"请输入这"<<n<<"个点的坐标:"<<endl;for(int i = 0; i < n; i++){cin>>S[i].x>>S[i].y;}Qsortx(S, 0, n-1);for(int i = 0; i < n; i++){Y[i].x = S[i].x;Y[i].y = S[i].y;}Qsorty(Y, 0, n-1);printarry(S, n);printarry(Y, n);mini = cp(S, Y, 0, n-1);cout<<"最近的兩個點是:"<<endl;cout<<"("<<S[Q[0]].x<<","<<S[Q[0]].y<<")"<<"<----->"<<"("<<S[Q[1]].x<<","<<S[Q[1]].y<<")"<<endl;cout<<endl;cout<<"最近点对的距离为:"<<mini<<endl;system("pause");return 0;}

算法分析

应用分治算法求解含有n个点的最近对问题,由于划分阶段的情况1和情况2可递归求解,情况3的时间代价是O(n),合并子问题解的时间代价是O(1),则算法的时间复杂度可由下边的递推式表示:

可得T(n)=O(nlogn)。

算法分析与设计——分治法最近点对相关推荐

  1. 分治法——最近点对问题

    最近点对问题 最近点对问题是利用分治法解决的经典问题之一. 问题描述 设在一个点集S中存在n个点,找出距离最相近的一对点p1和p2,最近点对可能不止一对,输出一对即可. 分析设计 在n个点中找出距离最 ...

  2. 【算法分析与设计】平面最近点对(含最近距离、最近点对、第一次分割点集合的输出)

    [问题描述] 给定二维平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小.使用递归与分治策略求解二维平面上的最接近点对问题.假设所有点的集合为S,m为S中所有点的x坐标的中 ...

  3. 【分治法】解决中位数问题、格雷码问题以及分治法直接折半存在的问题讨论————武汉理工大学算法分析实验1

    AlgorithmExperiment 算法分析课实验 分治法的核心思想是将问题分为若干子问题去,使规模一步步缩小,最终分到一步就能得出结果.要注意每个子问题需要性质相同而且相互不重复. 采用分治法完 ...

  4. 最近点对问题(蛮力法和分治法)

    最近点对问题(蛮力法和分治法) 1.一维空间 1.1蛮力法 1.2分治法 2.二维空间 代码参考链接: http://t.csdn.cn/flREB 1.一维空间 1.1蛮力法 代码: import ...

  5. 棋盘覆盖-经典的分治法问题

    棋盘覆盖-经典的分治法问题 一.问题概述 二.适用方法 三.代码展示 四.运行结果 五.算法分析 一.问题概述 在一个 2k×2k个方格组成的棋盘中,若恰有一个方格与其他方格不同,称该方格为特殊方格, ...

  6. 算法设计与分析 实验二 分治法求解最近点对问题

    分治法求解最近点对问题 一.实验目的与要求 1.实验基本要求 2.实验亮点 二.实验内容与方法 三.实验步骤与过程 (一)一些准备工作 1.实验流程 2.数据生成与去除重复点 (二)暴力穷举法 1.算 ...

  7. 深大算法设计与分析实验二——分治法求最近点对问题

    源代码: 深大算法设计与分析实验二--分治法求最近点对问题代码-C/C++文档类资源-CSDN下载 目录 实验问题 一.实验目的: 二.内容: 三.算法思想提示 产生不重复的随机点算法: 蛮力算法: ...

  8. 算法设计——用分治法查找数组元素的最大值和最小值、用分治法实现合并排序、最小费用问题、树的最大连通分支问题(代码实现)

    代码链接:pan.baidu.com/s/15inIth8Vl89R1CgQ_wYc2g  提取码:gf13 算法分析与设计第 1 次实验 时间 2020.3.31 地点 软件大楼 127 实验名称 ...

  9. 用分治法设计一个算法,在数组A中寻找最大元素和最小元素 Java代码

    算法分析与设计作业-- 用分治法设计一个算法,在数组A中寻找最大元素和最小元素 public class b1113 {static int min=Integer.MAX_VALUE;static ...

最新文章

  1. android 停用应用的命令,免Root使用ADB命令_停用手机系统应用
  2. OpenSSL简介及在Windows、Linux、Mac系统上的编译步骤
  3. 若依微服务版在Windows上通过jar包运行业务模块时提示:Failed to determine s suitable driver class
  4. Oracle Solaris 11 Express发布了
  5. linux vi 撤销与恢复,vi撤销与恢复
  6. sqlyog备份数据和导入备份数据
  7. 原创(网络克隆 )视频教程
  8. LY.JAVA.DAY12.Scanner
  9. FPGA 闪烁LED
  10. 【企鹅电竞直播源】浏览器抓取真实直播源地址(纯前端JS PHP解析源码)
  11. PYQT5:基于QsciScintilla的代码编辑器分析10--语法高亮颜色选择
  12. 计算机专业问卷调查,大学生计算机专业调查问卷.doc
  13. Isight多学科参数优化软件模块构成
  14. Apache Flink®极简教程: 架构及原理 Stateful Computations over Data Streams
  15. 紫外光谱分析的基本原理是什么
  16. 微信小程序测试应该注意的事项
  17. Oracle ERP AP模组中Vender 联系人信息查询语句
  18. Java 程序员月薪3.8万,需要技术达到什么水平?
  19. Qt Opengl 给两个立方体设置两中不同颜色
  20. ThinkPHP中的getLastSql函数---获取上次执行的SQL语句

热门文章

  1. 【任务脚本】0528京东618叠蛋糕任务脚本全自动脚本,京东任务全自动程序稳定运行,向大神致敬...
  2. SDUT-2132_数据结构实验之栈与队列二:一般算术表达式转换成后缀式
  3. 易优cms问一下大家 二级目录 真的完全不能装吗
  4. Android GIS开发系列-- 入门季(11) Callout气泡的显示
  5. 你能用微信小程序打开小程序了【附开发方法】
  6. android launchmode singleinstance问题
  7. 移动负载均衡技术(MBL)
  8. Android activity 参数传递
  9. QA:智能布线系统二十问
  10. [原创]微软拼音输入法2007(含64位版)