最近点对

28 篇文章 2 订阅
16 篇文章 0 订阅

看了最近点对问题,实现一下,不知是否有错。


#include <cmath>
using namespace std;



struct Point
{
	Point(float x, float y)
	{
		this->x = x;
		this->y = y;
	}
	float x;
	float y;
};


float dist(Point &a, Point &b)
{
	return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}


float min(float a, float b)
{
	return a > b ? b : a;
}

float min(float a, float b, float c)
{
	return min( min(a,b), c); 
}

float closetImp(Point *X, Point **Y, Point **T, int left, int right, int len)
{

	if( left + 1 == right)
	{
		return dist(X[left], X[right]);
	}
	else if(left + 2 == right)
	{
		return min( dist(X[left], X[left+1]), dist(X[left], X[right]), dist(X[left+1], X[right]) );
	}
	
	int center = (left + right) / 2;

	//左、右最短距离
	float disL = closetImp(X, Y, T, left, center, len);
	float disR = closetImp(X, Y, T, center+1, right, len);
	float minDis = min(disL, disR);
	
	//收集处于带中的点
	int pos = 0;
	for(int i = 0; i < len; i++)
	{
		if( abs(Y[i]->x - X[center].x) < minDis )
			T[pos++] = Y[i];
	}
	

	//计算带中点的距离
	for(int i = 0; i < pos; i++)
	{
		for(int j = i+1; j < pos; j++)
		{
			if(T[j]->y - T[i]->y > minDis)
				break;
			minDis = min(minDis, dist(*T[j], *T[i]) );
		}
	} 
	return minDis;
	
}
//简单插入排序
void sortX(Point *arr, int len)
{
	for(int i = 1; i < len; i++)
	{
		for(int j = i; j > 0; j--)
		{
			if(arr[j].x < arr[j-1].x)
			{
				Point tmp = arr[j-1];
				arr[j-1] = arr[j];
				arr[j] = tmp;
			}
			else
			{
				break;
			}
		}
	}
}
//简单插入排序
void sortY(Point **arr, int len)
{
	for(int i = 1; i < len; i++)
	{
		for(int j = i; j > 0; j--)
		{
			if( arr[j]->y < arr[j-1]->y)
			{
				Point *tmp = arr[j-1];
				arr[j-1] = arr[j];
				arr[j] = tmp;
			}
			else
			{
				break;
			}
		}
	}
}

float closet(Point *arr, int len)
{
	Point **Y = new Point*[len];
	Point **T = new Point*[len];
	
	float dis = 0.0;
	if(Y != NULL && T != NULL)
	{
	
		for(int i = 0; i < len; i++)
		{
			Y[i] = &arr[i];
		}
		sortX(arr, len);
		sortY(Y, len);

		dis = closetImp(arr, Y, T, 0, len-1, len);
		delete [] Y;
		delete [] T;
	}
	return dis;
}

原理:

1. 首先,按点的横坐标排序,这样,可以通过递归将所有点分成左右两部分(按x坐标)

2. 其次,递归计算左边点,计算右边点的最短距离,二者取最小记为minDis。(注:若一边只有一个点,则返回距离应该是无穷大)

3. 再者,画一个带,计算带中点。带的画法是:位于左右两边的点,若与中轴横坐标的差值小于minDis,则收集

4. 然后,由于从Y中收集,而Y已经按y坐标排好序了,因此,若y的差值大于minDis,则计算出来值必定大于minDis,因此舍弃。

5. 最后,计算带中横跨两个区间的点的距离,然后与minDis取最小值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值