一、求解最近点对问题
【问题描述】给定平面S上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。
(1)蛮力法求解最近点对问题
double ClosestPoints(vector<Point> a,int leftindex,int rightindex)
{ int i,j;
double d,mindist =INF;
for (i=leftindex;i<=rightindex;i++)
for (j=i+1;j<=rightindex;j++)
{ d=Distance(a[i],a[j]);
if (d<mindist)
mindist=d;
}
return mindist;
}
(2)分治法求解
1) 基本思路
2)步骤
- 对a中所有点按x坐标从小到大排序,将a中点集复制到b中,对b中所有点按y坐标从小到大排序。设求出a中最近点对距离为d。
- 如果a中点数少于4,则采用蛮力法直接计算各点的最近距离d。
3)算法
bool pointxcmp(Point &p1,Point &p2)
//用于点按x坐标递增排序
{
return p1.x<p2.x;
}
bool pointycmp(Point &p1,Point &p2)
//用于点按y坐标递增排序
{
return p1.y<p2.y;
}
double ClosestPoints11(vector<Point> &a,vector<Point> b,int leftindex,int rightindex)
//递归求a[leftindex..rightindex]中的最近点对
{ vector<Point> leftb,rightb,b1;
int i,j,midindex;
int leftminindex1,leftminindex2; //左边的最近点对
int rightminindex1,rightminindex2; //右边的最近点对
double d1,d2,d3,d;
if ((rightindex-leftindex+1)<4)
//少于4个点,直接用蛮力法求解
{ d=ClosestPoints(a,leftindex,rightindex);
return d;
}
midindex=(leftindex+rightindex)/2; //求中间位置
for (i=0;i<b.size();i++) //将b中点集分为左右两部分
if (b[i].x<a[midindex].x)
leftb.push_back(b[i]);
else
rightb.push_back(b[i]);
d1=ClosestPoints11(a,leftb,leftindex,midindex);
d2=ClosestPoints11(a,rightb,midindex+1,rightindex);
d=min(d1,d2);
//求中间部分点对的最小距离
for (i=0;i<b.size();i++) //将b中间宽度为2*d的带状区域内
//的子集复制到b1中
if (fabs(b[i].x-a[midindex].x)<=d)
b1.push_back(b[i]);
double tmpd3;
for (i=0;i<b1.size();i++) //求b1中最近点对
for (j=i+1;j<b1.size();j++)
{
if ((b1[j].y-b1[i].y)>=d) break;
tmpd3=Distance(b1[i],b1[j]);
if (tmpd3<d3)
d3=tmpd3;
}
d=min(d,d3);
return d;
}
//求中间部分点对的最小距离
for (i=0;i<b.size();i++) //将b中间宽度为2*d的带状区域内
//的子集复制到b1中
if (fabs(b[i].x-a[midindex].x)<=d)
b1.push_back(b[i]);
double tmpd3;
for (i=0;i<b1.size();i++) //求b1中最近点对
for (j=i+1;j<b1.size();j++)
{
if ((b1[j].y-b1[i].y)>=d) break;
tmpd3=Distance(b1[i],b1[j]);
if (tmpd3<d3)
d3=tmpd3;
}
d=min(d,d3);
return d;
}
4)算法分析