代码改变世界

最近点问题

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;
}