分治算法:最近对问题

  1. 问题
    [描述算法问题,首选形式化方式(数学语言),其次才是非形式化方式(日常语言)]
    对于平面上给定的N个点,给出所有点对的最短距离,即,输入是平面上的N个点,输出是N点中具有最短距离的两点
  2. 解析
    [问题的理解和推导,可用电子版直接在此编写,也可用纸笔推导,拍照嵌入本文档]
    将集合S分成两个子集S1和S2,每个子集中有n/2个点。然后在每个子集中递归地求其最接近的点对,在求出每个子集的最接近点对后,有两种可能情况:1集合S 中最接近的两个点都在子集S1或S2中2这两个点分别在S1和S2中。⑵对于第一点递归求解,如果最近点对分别在集合S1和S2中,那就分别取s1s2中最靠近中线的点,与中位点两两比较,并与子集S1或S2的最小路径对比,得出答案
  3. 设计
    [核心伪代码]

double divide_conquer(int start, int end, myPoint* X, myPoint* Y, myPoint& P1, myPoint& P2) {

if (end - start < 3)    //当点的数量小于等于3时,用暴力法。由于是按照x坐标来划分区域,固X数组的点的数量和位置君未发生改变,故用X数组不用Y数组
    return force(start, end, X,P1,P2);
int mid = (start + end) / 2; //按照x坐标的排序,从中间切开

int leftLen = 0, rightLen = 0, i, j; //leftLen,和rightLen分别指示左右两边点集的个数
myPoint* YL = new myPoint[(end - start + 1) ]; //保存中线左边的点集,按照Y坐标排序
myPoint* YR = new myPoint[(end - start + 1) ]; //保存中线右边的点集,按照Y坐标排序

for (i = 0; i <= end - start; i++) {    //遍历集合中每一个点,他们都是按照y的顺序进行排序的,若点的x坐标小于等于中线,则分割到左子集,否则分割到右子集
                                        //通过此操作YL和YR中的点的坐标依旧是按照y坐标排序好的
    if (Y[i].x <= X[mid].x) {
        YL[leftLen++] = Y[i];
    }
    else {
        YR[rightLen++] = Y[i];
    }
}

double left = divide_conquer(start, mid, X, YL,P1,P2);      //递归求左边部分的最短距离
myPoint leftP1 = P1;  //保存左支距离最小的两个点的坐标
myPoint leftP2 = P2;
double right = divide_conquer(mid + 1, end, X, YR,P1,P2);  //递归求右边部分的最短距离
double minDis;   //取小的一个
if (left < right) {
    minDis = left;
    P1 = leftP1;
    P2 = leftP2;
}
else {  //此时并不需要更新P1,P2的值,因为此时P1和P2的值就是右支的最小的一对点的坐标
    minDis = right;
}


myPoint* newY = new myPoint[(end - start + 1)];  //新建一个数组,用于保存以中界线为中心,宽度为 2*minDis 的垂直带形区域内的点

int newYLen = 0;
double leftBorder = X[mid].x - minDis;   //区域的左边界
double rightBorder = X[mid].x + minDis;  //区域的右边界

for (i = 0; i <= end - start; i++) {     //遍历Y集中所有点,满足条件则加入新集合,新集合的点的依然按照y坐标排序好

    if (Y[i].x >= leftBorder && Y[i].x <= rightBorder)
        newY[newYLen++] = Y[i];
}

for (i = 0; i<newYLen; i++) {       //在新集合中,判断每个点跟它后面的7个点的距离作比较,若小于则更新最小距离
    for (j = 1; j <= 7; j++) {
        if ((i + j)<newYLen) {  //加入条件,防止越界
            double dis = Distance(newY[i], newY[i + j]);

            if (dis < minDis) {
                minDis = dis;
                P1 = newY[i];
                P2 = newY[i + j];
            }
        }

    }
}

delete YL;
delete YR;
delete newY;

return minDis;

}
4. 分析
[算法复杂度推导]
假设n是2的幂
算法运行时间的递归式T(n)=2T(n/2)+f(n)
因此算法时间复杂度为O(nlogn)
5. 源码
[github源码地址]
https://github.com/zddhandsome/Algorithm/blob/main/%E5%88%86%E6%B2%BB%E6%B3%95%E6%9C%80%E8%BF%91%E5%AF%B9%E9%97%AE%E9%A2%98.cpp

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dd不是弟弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值