最近点问题
2009-06-12 15:51 htc开发 阅读(174) 评论(0) 编辑 收藏 举报快毕业了,本科阶段快要结束了。
散伙饭也吃了,毕业照也照了,心里有点感伤和失落。特别是看到朋友走的时候。 这段时间一直都很闲,毕业设计是一个ASP的题目,自己也没太认真去做。毕竟以后不想在这个方向发展。把毕设大概实现得差不多就开始着手研究算法了。手头上有三本算法书:一本是《算法和数据结构》(电子工业出版社),这本书出的比较早,主要是用PASCAL语言来讲的,看着稍微有点不太方便,但主要思想和思路都还算比较清晰,特别是第六章以后,将的知识都是很有难度的;还有一本比较新,《程序算法和技巧精选》(机械工业出版社),书中的算法都是经典算法,而且又是很基础的算法,还是有必要掌握到牢记的算法~ 还有一本就是严蔚敏的《数据结构C语言版》
看到第一本书中从递归和分治的由来,讲到递归和分治的哥们关系,最后给出了一道算法题----最近点问题。 我想这题大家都有影响吧,我大二时学C++的时候,我们学院的副院长还特意拿出来说了,只是当时没咋当回事,还是喜欢自己学东西~~
对于最近点问题,如果用蛮力法:即对每一个点求其最近点,然后求所有这些最近点种的最小,便是所求。这样做的话思路是很清晰,实现起来也方便,其时间复杂度为O(n*n).
下面介绍用分治递归的思想来求解最近点对问题。分治的方法就是把一个复杂的大问题,通过合理的分解,分成一个一个很小,比较容易解决的问题,最后把这些小问题的解合成,求出总体问题的解得思想。
该算法的自然语言描述如下:
1.如果 s.length=2 这两个点的距离便是最近
2.如果 s.length=1 无解
3.求出集合s的x坐标的中位数 并根据这个中位数m 把s分成s1和s2两个子区域 其中s1.x<m s2.x>m
4.对s1区域递归求最近点距离min1
5.对s2区域递归求最近点距离min2
6.min=min(min1,min2)
7.如果还有更短的距离的话,那这两个点必然一个在区域s1,一个在区域s2
并且,这两点p,q满足 m-p.x<min q.x-m>min
8.把所有满足这样的关系的p,q两两进行比较,求出距离最短的两点 且其距离为min_s1_s2
问题1: 如果在这两个区域的点过多的话,效率提不上来,还不如蛮力法来的方便
答: 根据鸽舍定理,这样的点最多只有6个,那么也就是说 最多只需要6*6的时间
9.判断min小还是min_s1_s2小 并输出结果
C++算法源代码如下:
#include <iostream>
#include <fstream>
using namespace std;
#define InitSize 500
//下面动态增加在该程序中并没用到 该程序只是表达该算法的思想
#define IncrementSize 100
class Point
{
public:
int x;
int y;
public:
Point(int _x=0,int _y=0):x(_x),y(_y){}
};
typedef Point* PointPt;
//用Stack结构表示集合s 当然也可以用set
class Stack
{
public:
PointPt *elem;
int base;
int top;
int length;
int middle_x;
public:
Stack();
void push(PointPt ele);
void pop(PointPt &ele);
int getLength(){ return length; }
};
inline Stack::Stack()
{
elem=new PointPt[InitSize];
base=top=0;
length=0;
middle_x=0;
}
void Stack::push(PointPt ele)
{
elem[top++]=ele;
length++;
}
void Stack::pop(PointPt &ele)
{
ele=elem[--top];
length--;
}
int main()
{
int cpair(Stack &s);
//从文件abc.txt中读取坐标点,文件中的数据是这样安排的
// 1 12 14
// 2 13 15 ……
ifstream infile("abc.txt");
Stack main_s;
int index;
int sum=0;
while(infile>>index)
{
PointPt pTemp=new Point;
infile>>pTemp->x;
infile>>pTemp->y;
main_s.push(pTemp);
//main_s.middle_x=((main_s.length-1)*main_s.middle_x+pTemp->x)/main_s.length;
sum+=pTemp->x;
}
main_s.middle_x=sum/main_s.length;
// cout<<main_s.elem[0]->x<<endl;
// cout<<main_s.middle_x<<endl;
cout<<cpair(main_s);
}
int cpair(Stack &s)
{
if(s.getLength()==2)
{
PointPt first,second;
s.pop(first);
s.pop(second);
int sub_x,sub_y;
sub_x=first->x-second->x;
sub_y=first->y-second->y;
return (sub_x*sub_x+sub_y*sub_y);
}
if(s.getLength()==1)
{
return 10000;
}
//construct s1 and s2
int middle;
middle=s.middle_x;
int i=0;
Stack s1,s2;
int sum1=0,sum2=0;
while(i<s.getLength())
{
if(s.elem[i]->x<middle)
{
s1.push(s.elem[i]);
//s1.middle_x=(s1.middle_x*(s1.length-1)+s.elem[i]->x)/s1.length;
sum1+=s.elem[i]->x;
}
else
{
s2.push(s.elem[i]);
//s1.middle_x=(s1.middle_x*(s1.length-1)+s.elem[i]->x)/s1.length;
sum2+=s.elem[i]->x;
}
i++;
}
s1.middle_x=sum1/s1.length;
s2.middle_x=sum2/s2.length;
int min1=cpair(s1);
int min2=cpair(s2);
int min=(min1<min2)?min1:min2;
//choose the point near l=middle in s1 and s2
Stack p1,p2;
i=0;
while(i<s1.getLength())
{
if(middle-s1.elem[i]->x<min)
p1.push(s1.elem[i]);
i++;
}
i=0;
while(i<s2.getLength())
{
if(s2.elem[i]->x-middle<min)
p2.push(s2.elem[i]);
i++;
}
i=0;
for(i=0;i<p1.getLength();i++)
for(int j=0;j<p2.getLength();j++)
{
int mid_sub_x;
int mid_sub_y;
mid_sub_x=p1.elem[i]->x-p2.elem[j]->x;
mid_sub_y=p1.elem[i]->y-p2.elem[j]->y;
int mid_distance=mid_sub_x*mid_sub_x+mid_sub_y*mid_sub_y;
min=(mid_distance<min)?mid_distance:min;
}
return min;
}