给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。 
		例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。 
		通过检查所有的n(n- 1 ) / 2对点,并计算每一对点的距离,可以找出距离最近的一对点。这种方法所需要的时间为(n2 )。我们称这种方法为直接方法。图1 4 - 1 3中给出了分而治之求解算法的伪代码。该算法对于小的问题采用直接方法求解,而对于大的问题则首先把它划分为两个较小的问题,其中一个问题(称为A)的大小为「n /2ù,另一个问题(称为B)的大小为「n /2ù。初始时,最近的点对可能属于如下三种情形之一: 1) 两点都在A中(即最近的点对落在A中);2) 两点都在B中;3) 一点在A,一点在B。假定根据这三种情况来确定最近点对,则最近点对是所有三种情况中距离最小的一对点。在第一种情况下可对A进行递归求解,而在第二种情况下可对B进行递归求解。 
		
				
if (n较小) {用直接法寻找最近点对 
		R e t u r n ; } 
		// n较大 
		将点集分成大致相等的两个部分A和B 
		确定A和B中的最近点对 
		确定一点在A中、另一点在B中的最近点对 
		从上面得到的三对点中,找出距离最小的一对点 
		图14-13 寻找最近的点对 
		
				
为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。 
		例2-8 考察图14-14a 中从a到n的1 4个点。这些点标绘在图14-14b 中。中点xi = 1,垂线x = 1如图14-14b 中的虚线所示。虚线左边的点(如b, c, h, n, i)属于A,右边的点(如a, e, f, j, k, l) 属于B。d, g, m 落在垂线上,可将其中两个加入A, 另一个加入B,以便A、B中包含相同的点数。假设d ,m加入A,g加入B。 
		设是i 的最近点对和B的最近点对中距离较小的一对点。若第三种情况下的最近点对比小。则每一个点距垂线的距离必小于,这样,就可以淘汰那些距垂线距离≥ 的点。图1 4 - 1 5中的虚线是分割线。阴影部分以分割线为中线,宽为2 。边界线及其以外的点均被淘汰掉,只有阴影中的点被保留下来,以便确定是否存在第三类点对(对应于第三种情况)其距离小于。用RA、RB 分别表示A和B中剩下的点。如果存在点对(p,q),p?A, q?B且p, q 的距离小于,则p?RA,q?RB。可以通过每次检查RA 中一个点来寻找这样的点对。假设考察RA 中的p 点,p的y 坐标为p.y,那么只需检查RB 中满足p.y- <q.y<p.y+ 的q 点,看是否存在与p 间距小于的点。在图14-16a 中给出了包含这种q 点的RB 的范围。因此,只需将RB 中位于×2 阴影内的点逐个与p 配对,以判断p 是否是距离小于的第三类点。这个×2 区域被称为是p 的比较区(comparing region)。 
		例2-9 考察例2 - 8中的1 4个点。A中的最近点对为(b,h),其距离约为0 . 3 1 6。B中最近点对为(f, j),其距离为0 . 3,因此= 0 . 3。当考察是否存在第三类点时,除d, g, i, l, m 以外的点均被淘汰,因为它们距分割线x= 1的距离≥ 。RA ={d, i, m},RB= {g, l},由于d 和m 的比较区中没有点,只需考察i即可。i 的比较区中仅含点l。计算i 和l的距离,发现它小于,因此(i, l) 是最近的点对。 
		为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。 
		1. 选择数据结构 
		为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。 
		每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。 
		程序14-8 点类 
		class Point1 { 
		friend float dist(const Point1&, const Point1&); 
		friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&, Point1&, float&); 
		friend bool closest(Point1 *, int, Point1&, Point1&,float&); 
		friend void main(); 
		p u b l i c : 
		int operator<=(Point1 a) const 
		{return (x <= a.x);} 
		p r i v a t e : 
		int ID; // 点的编号 
		float x, y; // 点坐标 
		} ; 
		class Point2 { 
		friend float dist(const Point2&, const Point2&); 
		friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&, Point1&, float&); 
		friend bool closest(Point1 *, int, Point1&, Point1&, float&); 
		friend void main(); 
		p u b l i c : 
		int operator<=(Point2 a) const 
		{return (y <= a.y);} 
		p r i v a t e : 
		int p; // 数组X中相同点的索引 
		float x, y; // 点坐标 
		} ; 
		所输入的n 个点可以用数组X来表示。假设X中的点已按照x 坐标排序,在分割过程中如果当前考察的点是X [l :r],那么首先计算m= (l+r) / 2,X[ l:m]中的点属于A,剩下的点属于B。计算出A和B中的最近点对之后,还需要计算RA 和RB,然后确定是否存在更近的点对,其中一点属于RA,另一点属于RB。如果点已按y 坐标排序,那么可以用一种很简单的方式来测试图1 4 - 1 6。按y 坐标排序的点保存在另一个使用类P o i n t 2 (见程序14-8) 的数组中。注意到在P o i n t 2类中,为了便于y 坐标排序,已重载了操作符<=。成员p 用于指向X中的对应点。
		
				 算法设计与分析
				算法设计与分析
 第二章——分治
第二章——分治
		 
		
				 #include 
				<
				algorithm
				>
				#include 
				<
				algorithm
				>
				 
 #include 
				<
				iostream
				>
#include 
				<
				iostream
				>
				 
 #include 
				<
				cmath
				>
#include 
				<
				cmath
				>
				 
 using namespace std;
using namespace std; 
 #define abst(a,b) (a>b?(a-b):(b-a))
#define abst(a,b) (a>b?(a-b):(b-a)) 
 typedef double TYPE;
typedef double TYPE; 
 #define Abs(x) ((x)>0 ? (x) : -(x))
#define Abs(x) ((x)>0 ? (x) : -(x)) 
 #define Sgn(x) ((x)
				<
				0 
				? (-1) : (1))
#define Sgn(x) ((x)
				<
				0 
				? (-1) : (1)) 
 #define Max(a,b) ((a)
				>
				(b) ? (a) : (b))
#define Max(a,b) ((a)
				>
				(b) ? (a) : (b)) 
 #define Min(a,b) ((a)
				<
				(b
				) ? (a) : (b))
#define Min(a,b) ((a)
				<
				(b
				) ? (a) : (b)) 
 #define Epsilon 1e-8
#define Epsilon 1e-8 
 #define Infinity 1e10
#define Infinity 1e10 
 const double PI
				=acos(-1.0);
const double PI
				=acos(-1.0); 

 struct MPOINT {
				struct MPOINT { 
 MPOINT(int xx
				=0,int 
				yy
				=0,int 
				tt
				=0):x(xx),y(yy),type(tt){}
    MPOINT(int xx
				=0,int 
				yy
				=0,int 
				tt
				=0):x(xx),y(yy),type(tt){} 
 int x;
    
				int x; 
 int y;
    int y; 
 int type;
    int type; 
 };
}; 
 MPOINT point[1000010];
MPOINT point[1000010]; 
 double result;
double result; 
 bool cmp(MPOINT s,MPOINT t)
bool cmp(MPOINT s,MPOINT t) 
 {
{ 
 return s.x<t.x;
    return s.x<t.x; 
 }
} 
 double len(MPOINT& a,MPOINT& b)
double len(MPOINT& a,MPOINT& b) 
 {
{ 
 return sqrt(double(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y)));
    return sqrt(double(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y))); 
 }
} 
 double mergepoint(int l,int r)
double mergepoint(int l,int r) 
 {
{ 
 double resultl
				=0,resultr=0,minlen=1000000000;
    double resultl
				=0,resultr=0,minlen=1000000000; 
 if(r
				>
				l+4) {
    
				if(r
				>
				l+4) { 
 int mid=(l+r)>>1;
        int mid=(l+r)>>1; 
 double tempdis;
        double tempdis; 
 resultl=mergepoint(l,mid);
        resultl=mergepoint(l,mid); 
 resultr=mergepoint(mid,r);
        resultr=mergepoint(mid,r); 
 minlen=min(resultl,resultr);
        minlen=min(resultl,resultr); 
 for(int i=mid;i>=l&
				&point
				[i].x>point[mid].x-minlen;i--) {
        for(int i=mid;i>=l&
				&point
				[i].x>point[mid].x-minlen;i--) { 
 for(int j=mid;j
				<
				=r
				&&point[j].x<point[mid].x+minlen;j++) {
            for(int j=mid;j
				<
				=r
				&&point[j].x<point[mid].x+minlen;j++) { 
 if(point[i].type!
				=point[j].type&&abst(point[j].y,point[mid].y)<minlen) 
				{
                if(point[i].type!
				=point[j].type&&abst(point[j].y,point[mid].y)<minlen) 
				{ 
 tempdis
				=len(point[i],point[j]);
                    tempdis
				=len(point[i],point[j]); 
 if(tempdis<minlen) {
                    
				if(tempdis<minlen) { 
 minlen
				=tempdis;
                        minlen
				=tempdis; 
 }
                    
				} 
 }
                } 
 }
            } 
 }
        } 
 }
    } 
 else
    else 
 {
    { 
 double distemp;
        double distemp; 
 for(int i
				=l;i<r;i++) 
				{
        for(int i
				=l;i<r;i++) 
				{ 
 for(int j
				=l+1;j<=r;j++) 
				{
            for(int j
				=l+1;j<=r;j++) 
				{ 
 if(j
				==i) 
				{
                if(j
				==i) 
				{ 
 continue;
                    continue; 
 }
                } 
 if(point[i].type!
				=point[j].type) 
				{
                if(point[i].type!
				=point[j].type) 
				{ 
 distemp
				=len(point[i],point[j]);
                    distemp
				=len(point[i],point[j]); 
 minlen
				=minlen>distemp?distemp:minlen;
                    
				minlen
				=minlen>distemp?distemp:minlen; 
 }
                
				} 
 }
            } 
 }
        } 
 }
    } 
 return minlen;
    return minlen; 
 }
} 
 int input()
int input() 
 {
{ 
 int n;
    int n; 
 scanf("%d",&n);
    scanf("%d",&n); 
 for(int i
				=0;i<n;i++) 
				{
        for(int i
				=0;i<n;i++) 
				{ 
 scanf("%d%d",&point[i].x,&point[i].y);
            scanf("%d%d",&point[i].x,&point[i].y); 
 point[i].type
				=0;
            point[i].type
				=0; 
 }
        
				} 
 for(int i
				=n;i<(n<<1);i++) 
				{
        for(int i
				=n;i<(n<<1);i++) 
				{ 
 scanf("%d%d",&point[i].x,&point[i].y);
            scanf("%d%d",&point[i].x,&point[i].y); 
 point[i].type
				=1;
            point[i].type
				=1; 
 }
        
				} 
 return n;
        return n; 
 }
} 
 int main()
int main() 
 {
{ 
 int cas,n,x,y;
    int cas,n,x,y; 
 scanf("%d",&cas);
    scanf("%d",&cas); 
 while(cas--) {
    while(cas--) { 
 result
				=0;
        result
				=0; 
 n
				=input();
        
				n
				=input(); 
 sort(&point[0],&point[n<<1],cmp);
        
				sort(&point[0],&point[n<<1],cmp); 
 double result
				=mergepoint(0,(n<<1)-1);
        double result
				=mergepoint(0,(n<<1)-1); 
 printf("%.3lf\n",result);
        
				printf("%.3lf\n",result); 
 }
    } 
 return 1;
    return 1; 
 }
} 
 
		 
	posted on 2009-01-04 20:04 
KNIGHT 阅读(2800) 
评论(1)  编辑 收藏 引用