最近对问题

本文主要介绍了最近对问题的两种算法,比较时间性能

最近对问题

  • 一.实验题目

    p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对

  • 二.实验目的

    • 进一步掌握递归算法的设计思想以及递归程序的调试技术
    • 理解这样一个观点:分治与递归经常同时应用在算法设计之中
  • 三.实验要求

    • 分别用蛮力法和分治法求解最近对问题
    • 分析算法的时间性能,设计实验程序验证分析结论
  • 四.算法实现分析及结果

    • 蛮力法

      • //与分治法的公共部分
        struct point{
            int x,y;
            point(int _x,int _y){
                x=_x;y=_y;
            }
        };
        double Distance(point a,point b)
        {
            return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
        } 
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10

        * ```c++
        //主要部分:双循环挨个遍历计算,取最小值
        for(int i=0;i<N;i++){
        for(int j=i+1;j<N;j++){
        if(ans>Distance(p[i],p[j])){
        ans=Distance(p[i],p[j]);
        }
        }
        }
      • 算法分析

        • 算法思想

          将每个点与其他点通过遍历求解距离,求出最小值

        • 时间复杂度分析

          时间消耗在每个点与其他所有点比较,(n-1)+(n-2)+…+(1)–>$\frac{(n-1)*n}{2}$–>O(${n^2}$)

      • 实验结果分析

      • 运行结果

    • 分治法

      • bool cmp(point a,point b)//按照纵坐标排序
        {
            return a.y<b.y;
        }
        
        1
        2
        3
        4
        5
        6

        * ```c++
        bool cmp1(point a,point b)//按照横坐标排序
        {
        return a.x<b.x;
        }
      • double Closest(point S[],int low,int high)//参数S[]是已经按横坐标排好序的
        {
            double d1,d2,d3,d;
            int mid,i,j,index;
            point P[8];
            if(high-low==1) //只有两个点的情况可以直接计算返回
                return Distance(S[low],S[high]);
            if(high-low==2){//只有三个点也可直接计算返回结果
                return min(Distance(S[low],S[low+1]),min(Distance(S[low+1],S[high]),Distance(S[low],S[high])));
            }
            mid=(low+high)/2;
            d1=Closest(S,low,mid);//计算左面部分
            d2=Closest(S,mid+1,high);//计算右面部分
            d=min(d1,d2);
            //cout<<d1<<" "<<d2<<" "<<d<<endl;
            index=0;
            //计算在划分部分左右部分的距离是否比两边的距离小
            for(i=mid;i>=low&&(S[mid].x-S[i].x<d);i--) P[index++]=S[i];
            for(i=mid+1;i<=high&&(S[i].x-S[mid].x<d);i++) P[index++]=S[i];
            sort(P,P+index,cmp);//按纵坐标进行排序
            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]);
                        d=min(d,d3);
                    }
                }
            }
            return d;
        }
        
      • 算法分析

        • 算法思想

          分治法,划分成两部分,分别计算各部分中的最近对,然后合并子问题,求解分别属于两部分中的点的距离是否会比两部分各自的最近对小

        • 时间复杂度

          n=2,3时–>O(1)

          n>3时–>T(n)=2T(n/2)+n–>O(n*$log_2n$)

      • 运行结果

  • 五.实验体会

    ​ 通过利用分治法求解最近对问题,熟悉了分治法的三个阶段,划分,求解子问题,合并子问题,划分是将初始问题划分成规模比原来小的同类型问题,求解子问题通常利用递归的方式,再把各个子问题合并起来,算法的效率在很大程度上依赖于合并这一部分。


最近对问题
http://kaikai12321.github.io/2022/06/10/最近对问题/
作者
Hou Kai
发布于
2022年6月10日
许可协议