算法设计与分析之最近对问题

实验项目

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

实验目的

(1) 进一步掌握递归算法的设计思想以及递归程序的调试技术;
(2) 理解这样一个观点:分治与递归经常同时应用在算法设计之中。

实验要求

(1) 分别用蛮力法和分治法求解最近对问题;
(2) 分析算法的时间性能,设计实验程序验证分析结论。

算法设计与实现

1.蛮力法

(1)基本思想
蛮力法求解最近对问题的过程是:分别计算每一对点之间的距离,然后找出距离最小的那一对,为了避免对同一对点计算两次距离,只考虑 i<j i < j 的那些点对(Pi,Pj)。
(2)算法设计

struct Point    
{       
    double x;       
    double y;    
};    
double ClosePoints(int n,Point a[],int &index1,int &index2)  
{            
    double d;            
    double Dist=10000;         
    for (int i=0;i<n-1;i++)         
    {              
        for (int j=i+1;j<=n-1;j++)              
        {                   
            d=(a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y);
            if(d<=Dist)                   
            {                        
                Dist=d;                        
                index1=i;                        
                index2=j;                   
            }              
        }         
    }  
    return Dist;      
}   

(3)复杂度分析
算法的基本操作是计算两个点的欧几里得距离。注意到在求欧几里得距离时,避免了求平方根操作,其原因是:如果被开方的数越小,则它的平方根也越小。所以,算法的基本操作就是求平方,其执行次数为:

T(n)=i=1n1j=i+1n2=2i=1n1(ni)=n(n1)=O(n2) T ( n ) = ∑ i = 1 n − 1 ∑ j = i + 1 n 2 = 2 ∑ i = 1 n − 1 ( n − i ) = n ( n − 1 ) = O ( n 2 )

2.分治法

(1)基本思想
我们用分治法解决最近对问题,就是将集合S分成两个子集S1和S2,每个子集中有n/2个点。然后在每个子集中递归的求其最接近的点对,在求出每个子集的最接近点对后,关键问题是如何实现分治法中的合并步骤,如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。但是,如果这2个点分别在S1和S2中,则对于S1中任一点p,S2中最多只有n/2个点与它构成最接近点对的候选者,仍需计算才能得到准确结果。
(2)算法设计

double DivPoints(point p[],int begin,int end)
{   
    int i,j;
    int n=end-begin+1;
    int m=(begin+end)/2;
    if(n==2)
        return Distence(p[begin],p[end]);//返回两个点距离
    if(n==3)//三个点直接求最近点并返回距离
    {
        double d1 = Distence(p[begin], p[begin+1]);
        double d2 = Distence(p[begin+1], p[end]);
        double d3 = Distence(p[begin], p[end]);
        if(d1<=d2 && d1<=d3)
            return d1;
        else if (d2 <= d3)
            return d2;
        else 
            return d3;
    }
    double left=DivPoints(p,begin,m);
    double right=DivPoints(p,m+1,end);
    double d=min(left,right);
    int k,l,flag=0;
    //找到以m为中心的与m横坐标距离小于sqrt(d)的点
    for(i=begin;i<=end;i++)
    {
        if(flag==0 && (p[m].x-p[i].x)<=sqrt(d))
        {
            flag=1;
            k=i;
        }
        if((p[i].x-p[m].x) <= sqrt(d))
            l=i;        
    }
    for (i=k;i<=m;i++)
    {
        for (j=m+1;j<=l && fabs((p[j].y-p[i].y))<sqrt(d);j++)
        {
            if(Distence(p[i],p[j]) <= d)
                d=Distence(p[i],p[j]);
        }
    }
    return d;
}

(3)复杂度分析
应用分治法求解含有n个点得最近对问题,其时间复杂性可由下面的递推式表示:

T(n)=2T(n/2)+f(n) T ( n ) = 2 T ( n / 2 ) + f ( n )
合并子问题的解的时间 f(n)=O(1) f ( n ) = O ( 1 ) ,由通用分治递推式的主定理得,
T(n)=O(nlog2n) T ( n ) = O ( n l o g 2 n )

实验结果与分析

随机生成一定数量的点,分别用蛮力法和分治法求解最近对问题,统计算法运行的时间。

(1)实验结果

点的个数蛮力法求解时间分治法求解时间
503.36422e-005s8.86672e-005s
1000.000122309s0.000157377s
5000.0029819s0.00102267s
10000.0124858s0.00237634s
50000.289743s0.0132567s

(2)实验分析

从实验结果可以看出,在点数规模较小时,蛮力法效率较高,当点数规模较大后,分治法效率明显比蛮力法要高。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值