C++用蛮力法与分治法解决最近对问题

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

蛮力法

简单起见,只考虑二维的情况并假设所讨论的点以标准笛卡尔坐标形式给出。因此,两个点pi(xi,yi)和pj(xj,yj)之间的距离是欧几里得距离(Euclidean distance):
C++用蛮力法与分治法解决最近对问题_第1张图片
蛮力法求解最近对问题的过程是显而易见的:分别计算每一对点之间的距离,然后找出距离最小的那一对。为了避免对同一对点计算两次距离,可以只考虑i

代码如下:

#include
#include
using namespace std;

double ClosestPoints(double x[],double y[],int n)
{
	double x1,x2,y1,y2;   //记载最近点对的下标
	double d,minDist=1000;   //假设最大距离不超过1000
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)   //只考虑i
		{
			d=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);   //计算距离 
			if(d<minDist)
			{
				minDist=d;
				x1=x[i],y1=y[i];
				x2=x[j],y2=y[j];
			}
		}
	}
	cout<<"最近的点对是<"<<x1<<","<<y1<<">和<"<<x2<<","<<y2<<">,";
	return minDist; 
}

int main()
{
	double x[50],y[50];
	double minDist;
	int n;
	cout<<"请输入点的个数:"<<endl;
	cin>>n;
	cout<<"请输入点集的坐标:"<<endl;
	for(int i=0;i<n;i++)
	{
		cin>>x[i]>>y[i];
	}
	minDist=ClosestPoints(x,y,n);
	cout<<"其距离为:"<<sqrt(minDist)<<endl;
    return 0;
}

算法ClosestPoints的基本语句是计算两个点的欧几里得距离,该语句的主要操作是求平方,其执行次数为:
C++用蛮力法与分治法解决最近对问题_第2张图片

分治法

在利用分治法思想解决此问题时,首先考虑将最近对问题进行分治,设计其分治策略。将集合S分成两个子集S1和S2,根据平衡子问题原则,每个子集中的点数大致都为n/2。这样分治后,最近点对将会出现三种情况:在S1中,在S2中或者最近点对分别在集合S1和S2中。利用递归分析法分别计算前两种情况,第三种方法另外分析。求解出三类子情况后,再合并三类情况,比较分析后输出三者中最小的距离。

代码如下:

#include
#include
#include
#include
#include
using namespace std;

struct point   //点结构 
{
	int x,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));
}
bool cmp1(point a,point b)   //按x坐标升序排列 
{          
    return a.x<b.x;
}
bool cmp2(point a,point b)   //按y坐标升序排列 
{          
    return a.y<b.y;
}
double Closest(point S[],int low,int high,point rec[])
{
    double d1,d2,d3,d;
    int mid,i,j,index;
    double x1,x2,y1,y2;   //记录点对的位置 
    point P[high-low+1];   //存放点集合
    point temp1[2],temp2[2];
    if(high-low==1)   //只有两个点,返回两点间的距离 
	{
	    rec[0].x=S[low].x;
		rec[0].y=S[low].y;
		rec[1].x=S[high].x;
		rec[1].y=S[high].y;             
        return Distance(S[low],S[high]);
    }
    if(high-low==2)   //只有三个点,求最近对距离 
	{            
        d1=Distance(S[low],S[low+1]);
        d2=Distance(S[low+1],S[high]);
        d3=Distance(S[low],S[high]);
        if((d1<d2) && (d1<d3))
	    {
	    	rec[0].x=S[low].x;
			rec[0].y=S[low].y;
            rec[1].x=S[low+1].x;
            rec[1].y=S[low+1].y;
			return d1;
        }else if(d2<d3)
	    {
	    	rec[0].x=S[low+1].x;
	    	rec[0].y=S[low+1].y;
	    	rec[1].x=S[high].x;
	    	rec[1].y=S[high].y;
            return d2;
        }
        else
	    {
	    	rec[0].x=S[low].x;
	    	rec[0].y=S[low].y;
	    	rec[1].x=S[high].x;
	    	rec[1].y=S[high].y;
            return d3;
        }
    } 
    mid=(low+high)/2;   //计算中间点 
    d1=Closest(S,low,mid,rec);   //递归求解子问题1 
    temp1[0]=rec[0];
    temp1[1]=rec[1];
    d2=Closest(S,mid+1,high,rec);   //递归求解子问题2 
    temp2[0]=rec[0];
    temp2[1]=rec[1];
    if(d1<d2)   //以下为求解子问题3
	{
		rec[0]=temp1[0];
        rec[1]=temp1[1];
        d=d1;
    }
    else 
	{
		rec[0]=temp2[0];
        rec[1]=temp2[1];
        d=d2;
    }
    index=0;
    for(i=mid;(i>=low) && (S[mid].x-S[i].x<d);i--)   //建立点集合p1
	{ 
        P[index++]=S[i];
    } 
    for(i=mid+1;(i<=high) && (S[i].x-S[mid].x<d);i++)   //建立点集合p2
    {    
		P[index++]=S[i];
	} 
    sort(P,P+index,cmp2);   //对集合P1和P2按y坐标升序排列                
    for(i=0;i<index;i++)   //依次处理集合P1和P2中的点 
	{
        for(j=j+1;j<index;j++)
		{
            if(P[j].y-P[i].y>=d)
            {
            	break;
			}else
			{
                d3=Distance(P[i],P[j]);
                if(d3<d)
				{
					rec[0].x=P[i].x;
					rec[0].y=P[i].y;
                    rec[1].x=P[j].x;
					rec[1].y=P[j].y;
                    d=d3;
                }
            }
        }
    }
    return d;
}

int main()
{
    point p[20];   //设定点的集合
    int n;
    double minDist;
    cout<<"请输入点的个数:"<<endl;   //输入点的个数
    cin>>n;
    cout<<"请输入点集的坐标:"<<endl;
    for(int i=0;i<n;i++)
    {
    	cin>>p[i].x>>p[i].y;
	}
	sort(p,p+n,cmp1);
	point index[2];
    minDist=Closest(p,0,n-1,index);
    cout<<"最小距离点对为:<"<<index[0].x<<","<<index[0].y<<">,<"<<index[1].x<<","<<index[1].y<<">"<<endl;
    cout<<"最小距离为:"<<minDist<<endl;   //输出点对的最小问题
    return 0;
}

应用分治法求解含有n个点的最近对问题,由于划分阶段的情况1和情况2可递归求解,情况3的时间代价是O(n),合并子问题解的时间代价是O(1),则算法的时间复杂性可用下面的递推式表示:
C++用蛮力法与分治法解决最近对问题_第3张图片
根据主定理可得:
在这里插入图片描述

你可能感兴趣的:(c++,c++,数据结构,算法)