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

Posted 姜姜csu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法——蛮力法之最近对问题和凸包问题相关的知识,希望对你有一定的参考价值。

  上次的博客写到一半宿舍停电了。。。。然而今天想起来补充完的时候发现博客园并没有自动保存哦,微笑。

  首先来看最近对问题,最近对问题描述的就是在包含n个端的集合中找到距离最近的两个点,当然问题也可以定义在多维空间中,但是这里只是跟随书上的思路实现了二维情况下的最近对问题。假设所有讨论的点是以标准的笛卡尔坐标形式(x,y)给出的,那么在两个点Pi=(Xi,Yi)和Pj=(Xj,Yj)之间的距离是标准的欧几里得距离:

                d(Pi,Pj)=sqrt( (X1-X2)2+(Y1-Y2)2 )

蛮力法的思路就是计算出所有的点之间的距离,然后找出距离最小的那一对,在这里增加效率的一种方式是只计算点下标  i<j  的那些对点之间的距离,这样就避免了重复计算同一对点间距离。下面是蛮力法解决最近对问题的算法:


 

使用蛮力法求平面中距离最近的两点

BruteForceClosetPoints(P)

//输入:一个n(n≥2)的点的列表P,Pi=(Xi,Yi)

//输出:距离最近的两个点的下标index1和index2

dmin    <—  ∞

for  i   <— 1 to  n-1  do

  for    j   <— i+1  to  n   do

    d   <— sqrt( (Xi-Xi)2+(Yj-Yj)2 )

    if   d<dmin;

      dmin=d;  index1=i;  index2=j;

return   index1,index2


  该算法的关键步骤是基本操作虽然是计算两个点之间的欧几里得距离,但是求平方根并不是像加法乘法那么简单。上面算法中,开平方函数导数恒大于0,它是严格递增的,因此我们可以直接只计算(Xi-Xi)2+(Yj-Yj)2,比较d2的大小关系,这样基本操作就变成了求平方。平方操作的执行次数是:

            n(n-1) ∈  Θ(n2

因此,蛮力法解决最近对问题的平均时间复杂度是Θ(n2

  


  下面是该算法的c++代码实现部分,在实现这个算法时,我碰到了三个问题:

  一是:怎么表示一个点集,因为最终返回的下标是集合中点的下标,要用的数据结构就是一维数组,但是点的xy坐标又要怎么表示呢,这里我在头文件中创建了struct类型的点结构,该结构拥有的成员变量就是x代表的横坐标和y代表的纵坐标,这样就可以直接创建该结构的一位数组进行计算了。

  二是:BruteForceClosetPoints(P)函数返回的是两个最近对下标的值,但是用return只能返回一个值,因此这里在BruteForceClosetPoints函数的参数表中增加了引用类型的变量  &index1,&index2。

  三是:在计算点间距离前,需要将最大值付给存储当前最小距离的变量dmin,但是我不记得怎么表示float类型的最大值,搜索之后发现c++的<float.h>头文件中定义了FLT_MAX这个常量表示float类型的最大值(其中也记录了double类型的最值,而int类型是记录在<limits.h>头文件中)。

  另外在实现时为更符合思路,我没有使用数组的0号空间,而是直接从1号空间开始使用。

  下面是源代码部分:

//头文件部分
#include<float.h>//该头文件中存储了float类型和double类型的最值
typedef struct Point{
    float x;
    float y;
};
void  BruteForceClosetPoints(Point P[], int n, int &index1, int &index2);



//源文件部分
#include <iostream>
#include "最近对问题头文件.h"
using namespace std;
int main(){
    Point P[4];
    for (int i = 1; i < 4; i++){
        cin >> P[i].x >> P[i].y;
    }
    getchar();
    /*
    cout << "您输入的点的坐标为:" << endl;
    for (int i =1; i <4; i++){
        cout<< "("<<P[i].x <<","<< P[i].y<<")     ";
    }
    */   
    int index1, index2;
    BruteForceClosetPoints(P, 4, index1, index2);
    cout << "最近对的两个点的下标为:" << index1 << "    " << index2<< endl;
    getchar();
    return 1;
}

void BruteForceClosetPoints(Point P[], int n, int &index1, int &index2){//由于要同时返回两个点的下标,因此这里将形参设置为引用变量
    float dmin = FLT_MAX;//常量FLT_MAX 来源于float.h头文件
    int i = 1,j=0;
    float d;
    for (; i < n-1; i++){
        for (j = i + 1; j < n; j++){
            d = (P[i].x - P[j].x)*(P[i].x - P[j].x) + (P[i].y - P[j].y)*(P[i].y - P[j].y);
            if (d < dmin){
                dmin = d;
                index1 = i;
                index2 = j;
            }
        }
    }
}

 

以上是关于算法——蛮力法之最近对问题和凸包问题的主要内容,如果未能解决你的问题,请参考以下文章

算法——蛮力法之顺序查找和蛮力字符串匹配

3.1.1蛮力法之选择排序

找犯人——蛮力法(算法)

算法笔记_016:凸包问题(Java)

算法设计与分析--求最大子段和问题(蛮力法分治法动态规划法) C++实现

算法笔记_008:选择排序和冒泡排序蛮力法