分治法求解最近点对问题,c++

分治法求最近点对

随机生成横纵坐标值均在1-10之间的30个浮点数,递归求出距离最近的一对点的坐标及其该两点距离值。
c++/vc++编译器

#include<iostream>
#include<math.h>
#include <stdlib.h>    //添加这个头文件是为了控制浮点数输出规范(如保留几位小数)
#include<iomanip> 
using namespace std;
struct point
{
	float x,y;
}P[30];
struct dpoint   //标记最近点对的距离及是哪两点
{
	double d;
	int p1,p2;
}dp[20];
dpoint Min(point *P,int m,int n); //递归求最近点对
double dis(point *P,int m,int n);//求两点间距离
dpoint all(point *P,int m,int n,double d);//求整个区间的最近点对
float R(float a, float b) {
    return ((float)rand()/RAND_MAX)*(b-a)+a;
}
int main()
{
	int i,j;
	float m;
	dpoint dp;
	cout<<"随机生成的30个点为:"<<endl;
	for(i=0;i<30;i++)  //随机生成坐标值均在1-10的30个点
	{
		P[i].x=R(1,10);
        P[i].y=R(1,10);
	}
	for(i=0;i<30;i++)                //按横坐标的大小排序
		for(j=1;j<(30-i);j++)
		{
			if(P[j-1].x>P[j].x){
				m=P[j-1].x;
				P[j-1].x=P[j].x;
				P[j].x=m;
			}
		}
	for(i=0;i<30;i++)                 //输出随机生成的30个点
	{
		cout<<"( "<<fixed<<setprecision(3)<<P[i].x<<" , "<<fixed<<setprecision(3)<<P[i].y<<" )\t";
		if((i+1)%5==0)                //每5个换一行
		cout<<endl;
	}
	dp=Min(P,0,29);                   //计算最近点对
	cout<<"最近点对为:( "<<P[dp.p1].x<<" , "<<P[dp.p1].y<<" )与( "<<P[dp.p2].x<<" , "<<P[dp.p2].y<<" )"<<endl;//输出最近点对
	cout<<"最近点对距离为:"<<dp.d<<endl;//输出最近点对的距离
	return 0;
}
dpoint Min(point *P,int m,int n)
{
	double d1,d2,d3,d;     //两点间距离
	if(m==(n-1))           //区间里只有两个点时
	{
		dp[0].d=dis(P,m,n);
		dp[0].p1=m;
		dp[0].p2=n;
	}
	else if(m==(n-2))      //区间里有三个点
	{
		d1=dis(P,m,m+1);
		d2=dis(P,m,n);
		d3=dis(P,m+1,n);
		if(d1<d2&&d1<d3){
			dp[0].d=d1;
			dp[0].p1=m;
			dp[0].p2=m+1;
		}
		else if(d2<d3){
			dp[0].d=d2;
			dp[0].p1=m;
			dp[0].p2=n;
		}
		else
		{
			dp[0].d=d3;
			dp[0].p1=m+1;
			dp[0].p2=n;
		}
	}
	else{                              //区间中超过3个点
		dp[1]=Min(P,m,(m+n)/2);        //求左区间的最近点对
		dp[2]=Min(P,((m+n)/2+1),n);    //求右区间的最近点对
		dp[0]=dp[1];
		if(dp[1].d>dp[2].d)
		dp[0]=dp[2];
		d=dp[0].d;
		dp[3]=all(P,m,n,d);            //求整个区间上的最近点对
		if(dp[3].d<d)
		dp[0]=dp[3];
	}
	return dp[0];
}
double dis(point *P,int m,int n)      //求两点间距离
{
	double q;
	q=sqrt((P[n].x-P[m].x)*(P[n].x-P[m].x)+(P[n].y-P[m].y)*(P[n].y-P[m].y));
	return q;
}
dpoint all(point *P,int m,int n,double d)       //求整个区间最近点对
{
	int i,j=0,k=4,mn,ii;  //ii用来标记p1中从第几个开始距离垂直线小于d
	mn=(m+n)/2;
	double d1;
	for(i=m;i<=mn;i++)       //垂直线x=(m+n)/2为分割线
		if(P[i].x>(P[mn].x-d))   //找p1区间横坐标离垂直线小于d的点p
		{
			if(j==0)
			ii=i;
			j++;
		}
	int jj=ii;
	for(;ii<(j+jj);ii++)    //依次对于p1区间符合的点p找p2区间在矩形区间的点q
		for(i=(mn+1);i<=n;i++)
		if(P[i].y>(P[ii].y-d)&&P[i].y<(P[ii].y+d)&&P[i].x<(P[mn].x+d)) 
		{
			d1=dis(P,ii,i);
			if(d1<d)
			dp[k].d=d1;
			dp[k].p1=ii;
			dp[k].p2=i;
			k++;
		}
	j=4;     //用j来标记第j对点中距离最短
	for(i=5;i<k;i++)
		if(dp[j].d>dp[i].d)
		j=i; 
	return dp[j]; 
}

运行结果如下
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值