最近点对问题,是分治法的一个典型应用,可以作为分治法入门的一个切入点。
最近点对问题的描述比较简单,在二维平面中,给定一堆点,求距离最近的一对点,思路是,讲这一堆点分为两部分,左域与右域,如何划分左域右域呢?我们知道,这一堆点,每一个点都有其横坐标,假如有十个点,对应十个横坐标,我们就取其中间数,然后分别对其左右域求最小值,关于如何对左右域求最小值问题上,别人采用的一般都是类似于快速排序的递归模型,我这里采用的是DFS方法来对其进行递归,分别求得其左右域的最小值,我们求得左右域的最小值后,还要考虑一点,假设此时的最小值为X,然而还有一个可能,左域里面,最靠近分界线的一个点,和右域里面最靠近分界线的一个点,其距离小于X,这样最小距离就并非X了,所以,还要考虑一段以分界线为中位线,左右长度各位X/2的矩形面积里面,是否有一对点距离小于X,然后便可以找到其最近点对。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAX=10000;
const int time=8;
float minLength=65535;
typedef struct
{
float x;
float y;
}Node;
Node a[MAX]={{-10,1},{-4,1},{-2,2},{-0.2,1},{0.3,1},{1.5,3},{3,1},{4,1}};
bool cmp(const Node &a,const Node & b )
{
if(a.x!=b.x)
return a.x<b.x;
return a.y<b.y;
}
float Length(int i,int j)
{
return std::sqrt((a[j].y-a[i].y)*(a[j].y-a[i].y)+(a[j].x-a[i].x)*(a[j].x-a[i].x));
}
void ClosestPair(int start,int end)
{
int i;
float len;
if(start==end)
return;
ClosestPair(start+1,end);
for(i=start+1;i<=end;i++)
{
len=Length(start,i);
minLength=min(minLength,len);
}
}
void Solve()
{
float mid;
int temp[MAX];
int i=0,k=0,j=0;
mid=(a[time/2-1].x+a[time/2].x)/2;
for(i=0;i<time;i++)
{
if(fabs(a[i].x-mid) <minLength)
{
temp[k++]=i;
}
}
//temp record the points between the field in middle
//k means the totla number in temp
for(i=0;i<k-1;i++)
{
for(j=i+1;j<=k-1;j++)
{
minLength=min(minLength,Length(temp[i],temp[j]));
}
}
}
int main()
{
int i;
/*for(i=0;i<time;i++)
{
cin>>a[i].x;
cin>>a[i].y;
}*/
//输入完毕
sort(a,a+time,cmp);
ClosestPair(0,time/2-1);
ClosestPair(time/2,time-1);
//minLength为求得左右两个区间的最近点对的距离
Solve();
cout<<minLength<<endl;
return 0;
}