您的位置:首页 > 其它

分治算法五(最近点对---杭电OJ 1007 Quoit Design)

2013-05-13 19:56 489 查看
1、问题描述

杭电OJ 1007链接:http://acm.hdu.edu.cn/showproblem.php?pid=1007

即给定坐标系上N个点,找到距离最短的两个点。

2、思路解析

----->如果直接利用两两点比较的话,复杂度太高,为O(n^2),会导致超时

----->简化问题:考虑一维数轴上点的情况,如果对这些点排序O(nlgn),那么最后只需要用O(n)时间就可以找到最小距离,所以总的时间复杂度就是O(nlgn)。

----->回到二维:是不是可以先排序再搜索呢?如果仿照一维的情况,会出现什么问题呢?

=====>>先试着根据 x 轴排序,此时平面上的数据点按照 x 轴已经排好了顺序,那么是不是简单的遍历就能找到最小距离呢?

=====>>二维情况下,距离不是单方面决定的,而是由x,y两个坐标一起决定的,在一个方向上距离最短,不代表最终结果距离最短

=====>>难道这样做不行吗?

=====>>可以顺着这个思路做,但是要修正一下。采用分治的方法。先根据 x 轴对数据点排序,然后从中值点对数组一分为二。分别找到左右两个集合中的最短距离。

然后还有可能存在最短距离的位置就是两个集合之间的区域。对于这个区域,可以把范围限制在【mid - D , mid + D】之间以缩小范围。同时对 y 轴排序,

找出范围在D之内的点,这些点都是可能存在最小距离的区域点。

----->时间复杂度:T(n) = 2*T(n/2) + O(n) = O(nlgn)

/* file: closest							*/
/* 1、find the closet distance oftwo points	*/
/* 2、using divide and conquer algorithm	*/
/* 3、sorting the points by x-coordinate	*/
/* 4、divide the points into two sets by
L: x = mid,where mid is the middle of
the points's x-coordinate.
set S1:on the left of line L
set S2:on the right of line L			*/
/* 5、conquer the two sets S1 and S2,
and find the minimum distance in set
S1 and S2. D = min(S1,S2)				*/
/* 6、combine:the minimum distance can also
be finded between set S1 and S2.
the x-coordinate is limited in
[mid-D,mid+D],and then sort the limited
points by y-coordinate. therefore, the
y-coordinate is limited in the length
of D									*/

/*	problem:HDU OJ 1007*/

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

#define MaxNum 100005

/*=====================================
Point:struct of a point
PointArray:input points
PointY	  :y-coordinate sorting
=======================================*/
struct Point
{
double x,y;
}PointArray[MaxNum],PointY[MaxNum];

/*=====================================
CmpX:compare of x-coordinate
=======================================*/
bool CmpX(Point a,Point b)
{
return a.x < b.x;
}

/*=====================================
CmpY:compare of y-coordinate
=======================================*/
bool CmpY(Point a,Point b)
{
return a.y < b.y;
}

/*=====================================
Minimun:return the minimum
=======================================*/
inline double Minimun(double a, double b)
{
return (a < b) ? a : b;
}

/*=====================================
Distance:return the distance between point a, b
=======================================*/
inline double Distance(Point a, Point b)
{
double Px = a.x - b.x;
double Py = a.y - b.y;
return sqrt(Px * Px + Py * Py);
}

/*=====================================
Closest:return the closest distance of the points
=======================================*/
double Closest(int left, int right)
{
//middle of the array
int mid = (left + right) >> 1;
//Minimun distance
double MinD;
int i, j, count;
//case of two points
if((right - left) == 1) return Distance(PointArray[left], PointArray[right]);
//case of three points
else if((right - left) == 2)
{
MinD = Minimun(Distance(PointArray[left], PointArray[right]), Distance(PointArray[left + 1], PointArray[right]));
return Minimun(Distance(PointArray[left], PointArray[left + 1]), MinD);
}
//conquer
MinD = Minimun(Closest(left, mid), Closest(mid + 1, right));
//find the points of x-coordinate in [mid - MinD, mid + MinD]
for(i = left, count = 0; i <= right; i++)
if(fabs(PointArray[i].x - PointArray[mid].x) <= MinD)
PointY[count++] = PointArray[i];
//sorting PointY by y-coordinate
sort(PointY, PointY + count, CmpY);
//Attention:==> for 2-D points,must using two-flod (for) to find the every possible point
for(i = 0; i < count; i++)
for(j = i + 1; j < count; j++)
{
if(fabs(PointY[i].y - PointY[j].y) >= MinD) break;
MinD = Minimun(MinD, Distance(PointY[i], PointY[j]));
}
return MinD;
}

void main()
{
int N, i;
double MinD;
while(cin>>N,N)
{
for(i = 0; i < N; i++)
scanf("%lf%lf",&PointArray[i].x,&PointArray[i].y);
sort(PointArray, PointArray + N, CmpX);
MinD = Closest(0,N-1);
printf("%.2lf\n",MinD/2);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: