看了最近点对问题,实现一下,不知是否有错。
#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取最小值。