QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2914|回复: 0
打印 上一主题 下一主题

距离最近的点对

[复制链接]
字体大小: 正常 放大
韩冰        

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:18 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。
' L# s! P3 \0 Y1 O4 j/ |" z, J( A) w
9 o! S/ d% X* A7 _" M- ~7 n例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。/ V1 H/ D: {) n, x2 p
4 F# d. Y6 o6 A# G3 p
通过检查所有的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进行递归求解。# Y( O6 u: S7 q% z8 J$ D

  t; [3 j, V/ a& h% D' ~
! v- a; P1 H* r4 ?8 j4 Wif (n较小) {用直接法寻找最近点对+ H5 ^/ U0 V' y. c9 M

$ ^* S0 k, q8 X& Y( u$ I% p2 p. B& QR e t u r n ; }
* Q7 r! w- H8 X, c! \/ ~' A: O$ ~1 S# c4 {% \- i% o
// n较大5 x5 Y8 v: x9 W( X0 Q% U- J

: Z3 E* }5 I, \. b3 y将点集分成大致相等的两个部分A和B- j0 A, I" l  ~3 W) S( h

% k/ z6 K3 R$ E1 _  \5 i确定A和B中的最近点对" W0 R% p& N. l4 R& [9 J
) c% ~7 L- P- Z" [  U  S
确定一点在A中、另一点在B中的最近点对
( r$ l5 Z& ?" n7 R' j. J8 p9 f9 l& X; G
从上面得到的三对点中,找出距离最小的一对点! _7 Y: E( _, w. b0 Z) a. B/ M

1 ~# O. ^# Y2 f图14-13 寻找最近的点对
/ p; `$ C# Y. J2 D: n  w3 [. @" c
9 ]8 m% n0 o2 u' q$ K8 Q3 y/ i
' [  t; m0 B0 l: a9 d为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。
) G. o0 i/ B8 @1 i
3 E4 g" _7 T( ?( v6 ?例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。: c3 k, e) F4 y
# o1 U, E, L7 d6 a& t" K& [
设是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)。
6 ^6 V4 w: ]/ x/ I7 \2 q
( Y* r  R6 i2 R9 k例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) 是最近的点对。
, j1 W/ q0 l0 g" R, s' r+ F* k5 I2 z- e+ w( _6 O/ M
为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。) {! z: `& N% H7 l; Z
& j& ^7 s- c2 N
1. 选择数据结构
0 p; Y) {6 W4 A* S2 j1 r8 |  h3 q7 u" d3 |9 s# K
为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。; O% d6 S# K- v3 A
3 K, q* P4 r8 s3 _4 o* Y
每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。- l/ z. s' u2 {. ?

# [" l: l/ L! b) N4 _/ k. a程序14-8 点类2 p8 V! B+ |( o  j, Y0 y

# d( K4 d3 ~- n1 H; D+ gclass Point1 {
, J4 |' B6 s- m! ^$ M# [8 X+ O) o% G% W( g
friend float dist(const Point1&amp;, const Point1&amp;);
* r- b" d$ o/ o* |8 l1 Z, ^
: x$ U1 o* H8 E) t) `, Wfriend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);! g' }  ]( d# x3 E; r) f7 I

6 _+ @5 U( ?; m8 V9 F8 Yfriend bool closest(Point1 *, int, Point1&amp;, Point1&amp;,float&amp;);3 b9 \" V- X9 ?' C5 k3 H  c
7 A6 M& y! S0 b& M# a" l
friend void main();8 [: q: {5 w) u) S- l* q3 X* D

2 R6 x  j; F; X, x" B+ T3 yp u b l i c :
1 D  Q& i9 o% N9 n" @1 X& c7 K- a, z" E  n
int operator&lt;=(Point1 a) const
% v9 z9 v% I! r( k3 D/ h9 P( w0 `+ G. N# r, E5 ]- t; I. X
{return (x &lt;= a.x);}
/ H0 y7 e. P2 o& j4 f! K' d, B" d! \+ ~8 W& v
p r i v a t e :: J' a9 T# B% u# |8 D/ ]: d

2 h6 V8 f( u: D2 C7 ^; nint ID; // 点的编号
' v% W  U( x$ \5 W$ r2 v& H" T# v
- V. f$ \1 p- Ofloat x, y; // 点坐标
0 Q" d. C9 g9 V; K3 \! j
& l( `! {( X. y/ W- i4 E5 V7 u} ;6 {' E: E# z8 r1 ?) z/ A
4 ~! `* {0 P& ^, y/ f5 e! v0 v
class Point2 {
0 J( @/ D  m" f6 H( P* s! m& f9 t- B2 O% M3 _
friend float dist(const Point2&amp;, const Point2&amp;);9 ~8 g9 a) k, N) V" X
& K- g! _% S  d1 ]+ \/ R) G6 A
friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);  E% {0 o& y1 G9 ~
* H1 o) Y1 h' S! ]  ?/ h
friend bool closest(Point1 *, int, Point1&amp;, Point1&amp;, float&amp;);0 D' @- H% u0 a, T) J1 B* r: Z3 h% c* d

' S. |* W. S" f/ xfriend void main();
' Y+ q; c' m) T( |. C# ^
! e8 p5 T# Q8 n- sp u b l i c :5 k  K2 k' s* e
: E( D! \6 R# [
int operator&lt;=(Point2 a) const3 s- [- S/ _8 q

' e2 ?7 B# @2 Q# A0 y% O+ b8 H{return (y &lt;= a.y);}
" t# ~" i$ |$ j$ w$ O# o; W
- f4 _. ^8 y) u) V' _3 fp r i v a t e :# Y) z0 K  V+ C+ V8 W6 @
! F, c2 X) p3 @" v
int p; // 数组X中相同点的索引
5 Y! {$ G& I1 {; D, D/ s4 `. N" @3 `
float x, y; // 点坐标
' P+ ~  Q- l2 x. V
7 C* k" o2 Q3 Q0 h& [1 H} ;
2 f, M  I! R  J  t# v
- ?$ Y/ H, |) _5 U所输入的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中的对应点。
* r; e7 a8 f: E7 X% K) t& F' E0 N, v1 R5 g
确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数d i s t (见程序1 4 - 9 )来计算点a, b 之间的距离。T可能是P o i n t 1或P o i n t 2,因此d i s t必须是P o i n t 1和P o i n t 2类的友元。
: ~0 s; [  M5 l5 ]; E& c# ^# q) u& r: Y% D
程序14-9 计算两点距离
  X& F( A( V  C& \: ^- J! W: k3 y7 L
template<CLASS T>
; l! c5 ~$ k" _2 ^% Z9 n
6 w4 O9 D; P* w3 t* `inline float dist(const T&amp; u, const T&amp; v), C# o8 r$ f5 @; t# O

# ^+ ]: `8 d& o3 A7 ?% v. S{ / /计算点u 和v之间的距离
* |4 c$ j  M$ M' y; L) L, p0 I9 E( i7 p' ^9 f
float dx = u.x-v. x ;
$ B4 }' r6 w' Q4 b; i5 m( B" s
" z, P1 |, ]; r: R& cfloat dy = u.y-v. y ;
6 i# b+ O7 L2 ?( N: [  y2 B) U
5 s8 X: O( q2 z( @return sqrt(dx * dx + dy * dy);6 M9 X* G' d6 X# e* _: b

% |3 |+ k! {% \# B}
& b! [( n" q6 @" b
) ~3 j. z5 H2 I& x1 |9 z如果点的数目少于两个,则函数c l o s e s t (见程序1 4 - 1 0 )返回f a l s e,如果成功时函数返回t r u e。当函数成功时,在参数a 和b 中返回距离最近的两个点,在参数d 中返回距离。代码首先验证至少存在两点,然后使用M e rg e S o r t函数(见程序14-3) 按x 坐标对X中的点排序。接下来把这些点复制到数组Y中并按y 坐标进行排序。排序完成时,对任一个i,有Y [i ] . y≤Y [i+ 1 ] . y,并且Y [i ] .p给出了点i 在X中的位置。上述准备工作做完以后,调用函数close (见程序1 4 - 11 ),该函数实际求解最近点对。1 A4 V/ X" a) h3 B7 ^; B* W

+ ~0 E$ N& `  J/ B程序14-10 预处理及调用c l o s e( [. T: K/ z3 `7 K/ q
; L1 ?8 n5 R% A5 ~' ?/ J
bool closest(Point1 X[], int n, Point1&amp; a, Point1&amp; b, float&amp; d)0 |% O0 f% l0 w5 ]' H

+ x# W, d" Q: v{// 在n &gt;= 2 个点中寻找最近点对
6 H: [3 R9 r( Q3 X' M+ U
' {! r2 w( i1 v$ S) i3 s. E// 如果少于2个点,则返回f a l s e
9 b$ V4 G# x2 ?: |9 q' B- z8 ~# p* |$ T. T" b7 s
// 否则,在a 和b中返回距离最近的两个点8 @2 U: Y. \9 i7 Q/ V6 ?
" g2 T5 A- Z; m$ I
if (n &lt; 2) return false;
& E7 W$ L) c  G7 @( _# m* p& [% W2 n, r+ W+ w' ^, q
// 按x坐标排序2 q. \- X2 x; p

3 @" v9 T* o  Y0 J" z5 }4 NM e r g e S o r t ( X , n ) ;: A% e+ i0 b, d8 Q

7 u! g; N9 ~3 U! ?: W6 Z// 创建一个按y坐标排序的点数组" L! ~. k- Q0 s' [! U

6 @- h/ j$ o8 y* g! Y. c' b- `( ^Point2 *Y = new Point2 [n];& b" L, [% V; B7 y5 `; ~
8 S! L1 ^% y9 V2 q
for (int i = 0; i &lt; n; i++) {; d8 l0 t7 C, l4 `$ p
, ^- d1 a/ r7 z' V6 |+ B
// 将点i 从X 复制到Y
/ p8 |6 C: L  V- e9 q
( S5 ]2 v( Q. {0 l7 YY.p = i;
- F2 q! Y+ K/ ^+ i# j+ [& |( Q6 {
* u% ^( B/ o: e- E& s; m6 j! ]Y.x = X.x;" Z- d+ f( e1 X( D2 S

9 `( R+ G8 E& |* C1 tY.y = X.y;7 ], _# `9 [* C2 y* |4 C
: R3 E$ P5 D: T$ V- A4 j
}6 m2 N+ [9 M! g- O
! ?7 [6 M1 n* s* }* e% j
M e r g e S o r t ( Y,n); // 按y坐标排序
; L; u" M2 T" N6 P  c) V1 k! t
# B9 [  ^, l1 x// 创建临时数组" C: I0 s# f$ h% \9 {! p) Y& X
" H, ]6 z2 {! q8 T
Point2 *Z = new Point2 [n];
) J4 T1 j8 u# P* I
- @1 Y! ]9 l5 H  V. v// 寻找最近点对
0 N+ p0 w/ B! T: g  }: X5 g2 F( q0 m: W: u9 W( `8 i
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ;
" J6 y, Q0 O8 e' i6 [4 X0 Y4 J$ o8 M7 k
& B  w5 q9 S  s) b4 c// 删除数组并返回
$ A) \! i, L. U# q7 ]  |+ I% z* \" H
delete [] Y;% U1 a, b8 X( v) d% J; o  b
  x1 I) `8 P7 N6 z
delete [] Z;
9 I+ Q; d4 A0 k. l. d
: j( C1 Q2 h. l8 I# y& p) u6 Nreturn true;
& v: b& g- I9 H$ N, [' M: n# i9 ?' O+ D
}7 u7 _! v# {: z; r; \1 q' i, o7 Z" ^$ |

4 n2 }( ^  M4 S; o, T程序1 4 - 11 计算最近点对' G  M! y! l$ b2 H* X1 J

. s. y' X+ M3 z# n) i1 ^& ovoid close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1&amp; a, Point1&amp; b, float&amp; d)% o6 E, T& d: f; E/ L  N" t9 x
3 j7 E  Z3 Q0 ~5 c1 E' p. x
{//X[l:r] 按x坐标排序
4 ]0 b1 F  m/ y
" R' ^9 O2 S- e* i* E- ?9 v//Y[l:r] 按y坐标排序
7 C$ X# H0 C( j) _) a+ Y5 l. _% g, {+ c
if (r-l == 1) {// 两个点. O, x8 q6 k' b( w1 I9 h/ j( Q7 X
* E% [" G1 K1 a: G( P$ l9 P
a = X[l];
8 i: H' z; d1 `+ m( L% ^$ x$ ^7 G- ]# I7 G) d, F
b = X[r];
( d$ ]) |" h0 j, B" d; r7 t$ d7 P3 O8 P: H
d = dist(X[l], X[r]);
2 D2 @  u. T* P$ ^
  [1 P- y" {3 F# H) ?' M' Vr e t u r n ; }) s' B% t; P& q6 ]; L' i
' T; @$ ^2 C/ R
if (r-l == 2) {// 三个点
5 z% N$ V& L7 N; d
' K" o6 T5 d8 ~// 计算所有点对之间的距离0 C- q# o# X  j3 A2 d

: h' v. l+ j) R2 D" pfloat d1 = dist(X[l], X[l+1]);% w+ v6 F; H& }- e8 }# \" U. h
6 w6 A4 _, w& P9 y
float d2 = dist(X[l+1], X[r]);1 g7 s6 _; E& v; Y% a% V

! z( @3 l6 F5 S, C  W9 ~float d3 = dist(X[l], X[r]);  y6 ?8 M! k9 x6 m' {* U6 ^4 E
( r, V4 f; C: s5 r; t' ?+ Z
// 寻找最近点对
5 u' @' B* R7 W4 L+ x+ F- d, h! U' {' Q
if (d1 &lt;= d2 &amp;&amp; d1 &lt;= d3) {
( I# i* Q. S. `9 ~$ v. m) N) u) [, _  U% C  ?$ B- ?
a = X[l];
) _& a' c) E& `' P; }! e  y
- T: Z* l3 u4 p! {% o8 zb = X[l+1];1 N) J' H& i  Z3 V4 z5 P+ _
5 r4 ^- U2 z  I' K+ F9 J; e
d = d1;
' Q- }5 p9 J8 r$ g; p4 {- ~; a: J
5 G) K* d3 z" O" s0 Wr e t u r n ; }
. u& g0 j4 D" v- B" W( h
9 ^% M9 {0 ]% e1 a* z* E. qif (d2 &lt;= d3) {a = X[l+1];
7 ?1 I* z  d; m; y4 ?. s1 @
8 b3 ~1 C4 j7 Wb = X[r];
9 O6 L+ Y0 [, [8 Y% I: p) _; i. E: I  l: H# S
d = d2;}
. c9 T/ S) B1 o9 k- A: ~4 H1 W# D2 J
else {a = X[l];
1 L) i' V' L  Q! E2 g! K0 M! F
7 e  p7 `6 d; Y7 c" ub = X[r];
; q% Z. {( U) G- }7 d3 P, V* U5 Q; N( `
d = d3;}3 L7 T- E, }" T: Z% v

1 D1 {8 X' ]. R2 V( r' lr e t u r n ; }; F/ P) A0 [4 a$ t- f  \+ Q
9 h, ]" B+ K0 ^
/ /多于三个点,划分为两部分
: h' i; I6 z; u6 P. W) \6 M1 V
3 x5 _- e+ U  vint m = (l+r)/2; // X[l:m] 在A中,余下的在B中
2 T+ H0 ?& A* ^! U
# i3 N$ p! m1 i// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表6 X# F/ U7 ]# [: r
# V) t* j( ^% B5 p+ J5 L" e) o
int f = l, // Z[l:m]的游标
" u- M& I3 [, h& H( m' J* `5 g$ b9 R* [2 F& z/ S- d: a5 l; |
g = m+1; // Z[m+1:r]的游标
* C5 [# C4 ^! {/ C3 W& |; R7 }" Z: ~/ l
for (int i = l; i &lt;= r; i++)
* h# T) d$ K, [# q5 H9 X
% c8 D7 f; S% r4 A4 i7 l/ uif (Y.p &gt; m) Z[g++] = Y;, w' a- {: G2 R7 e3 j6 U$ j
& H5 Q" ?5 L& V0 ~
else Z[f++] = Y;
( y+ H- V1 j, O4 E# ~* Z" v
7 q' L, g6 v0 Z1 K// 对以上两个部分进行求解: u/ R  F4 F% d9 H5 i( }* Y

" u( {/ i- [& V" U+ b1 v- wc l o s e ( X , Z , Y, l , m , a , b , d ) ;7 _4 H  j/ I( X6 r

# ~, z  h4 h% e- afloat dr;  X6 J+ w/ Z1 j6 \- C

# K$ i: A) J$ J" U7 N4 X6 ePoint1 ar, br;" O& C! _" J4 N6 k; G* H) a6 S

& s; v5 J7 H- f0 |: @! W: z% Hc l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;
6 s8 G7 Z9 W$ z; i
% d, E5 K# K* a4 e# j- |// (a,b) 是两者中较近的点对; j3 y# a5 l6 y# `2 c( \
1 v$ r, h: n, _( }& A- P2 A
if (dr &lt; d) {a = ar;; s0 P( B( K! j. H3 B# o

3 |4 A* I' l0 ?, Q+ {) vb = br;
$ R! N( Q5 B  t; I5 j0 t9 X2 B9 t' r+ C
d = dr;}
: L; |7 q& e& {% C, h; O3 W, F4 s+ q7 y% m. e8 W0 X
M e r g e ( Z , Y,l,m,r);// 重构Y
9 m- Y# [0 r/ ^% V9 L7 z6 p/ E
/ /距离小于d的点放入Z
* V2 o" h+ Q4 y2 A  P6 u4 n3 S# o" I: O, o+ F( b: l3 T
int k = l; // Z的游标* [1 _: \" e' O  U0 a1 V

$ I) b/ k; v# K# zfor (i = l; i &lt;= r; i++)* y7 l( Y6 ~- x5 j1 }6 G# e

4 C+ B- F8 H# D* a- L0 M+ lif (fabs(Y[m].x - Y.x) &lt; d) Z[k++] = Y;6 ]4 W& C' J, z" m

% [$ F7 B) E' i' h6 P7 _// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对
& P4 }' z5 ~' A, c5 e
# v4 x* a7 {. m$ B# U7 jfor (i = l; i &lt; k; i++){
6 K% ~# q; f: S: D4 |9 f0 L: L: p8 @- u. R
for (int j = i+1; j &lt; k &amp;&amp; Z[j].y - Z.y &lt; d;) c! P% G8 c0 R, R2 C: _# T0 |
+ d" [! d; {6 _( @! |
j + + ) {% }; M1 z/ P9 \9 k9 \' J8 e' j
1 P' F8 I& x9 l% @' x
float dp = dist(Z, Z[j]);6 e( }+ o! l* ^/ q8 Z% z
$ p& H7 W7 Y! I" A$ m4 A, v3 D! [
if (dp &lt; d) {// 较近的点对( h2 x, Q! {3 }; C  e

4 Q7 `4 }+ P* b) Nd = dp;
5 D0 O3 ~0 e: u  K& {+ l7 A/ Z0 C$ n' B8 e
a = X[Z.p];
5 w2 E+ U+ M0 _3 H/ B+ v$ ^2 k% C6 {, Q
b = X[Z[j].p];}
5 \. x4 b0 _- N. e
; m4 I' ^) v3 N; d5 O! }+ p6 n) ~}5 O" l1 b  I8 \  M* G  ^

- ^( L! J) o: \+ Z}9 {5 k& w3 d8 r0 O. @% P

7 V" c9 _" r" z8 V6 o% W: F: Q}
6 f2 D5 r& @  s  P" ^2 W
0 W7 J/ G/ D: b5 r0 Y9 d  p函数c l o s e(见程序1 4 - 11)用来确定X[1:r] 中的最近点对。假定这些点按x 坐标排序。在Y [ 1 : r ]中对这些点按y 坐标排序。Z[ 1 : r ]用来存放中间结果。找到最近点对以后,将在a, b中返回最近点对,在d 中返回距离,数组Y被恢复为输入状态。函数并未修改数组X。
: y3 v, i) f7 r; m' r# l' ]& X  W) r/ I! O# h! i4 P, P  x% D2 S
首先考察“小问题”,即少于四个点的点集。因为分割过程不会产生少于两点的数组,因此只需要处理两点和三点的情形。对于这两种情形,可以尝试所有的可能性。当点数超过三个时,通过计算m = ( 1 + r ) / 2把点集分为两组A和B,X [ 1 : m ]属于A,X [ m + 1 : r ]属于B。通过从左至右扫描Y中的点以及确定哪些点属于A,哪些点属于B,可以创建分别与A组和B组对应的,按y 坐标排序的Z [ 1 : m ]和Z [ m + 1 : r ]。此时Y和Z的角色互相交换,依次执行两个递归调用来获取A和B中的最近点对。在两次递归调用返回后,必须保证Z不发生改变,但对Y则无此要求。不过,仅Y [ l : r ]可能会发生改变。通过合并操作(见程序1 4 - 5)可以以Z [ 1 : r ]重构Y [ 1 : r ]。- V8 [  s5 x# D6 M% A" [

+ E. F' I. G, s2 q为实现图1 4 - 1 6的策略,首先扫描Y [ 1 : r ],并收集距分割线小于的点,将这些点存放在Z [ 1 : k - 1 ]中。可按如下两种方式来把RA中点p 与p 的比较区内的所有点进行配对:1) 与RB 中y 坐标≥p.y 的点配对;2) 与y 坐标≤p.y 的点配对。这可以通过将每个点Z [ i ](1≤i &lt; k,不管该点是在RA* Q7 T0 S2 n/ i1 U  v
8 j6 P, B3 A  v  A3 F
还是在RB中)与Z[j] 配对来实现,其中i<j 且Z [ j ] . y - Z [ i ] . y< 。对每一个Z [ i ],在2 × 区域内所检查的点如图1 4 - 1 7所示。由于在每个2 × 子区域内的点至少相距。因此每一个子区域中的点数不会超过四个,所以与Z [ i ]配对的点Z [ j ]最多有七个。" G# R( \7 K: o/ D

; `1 {! A) l& V8 \2. 复杂性分析
! Q3 L$ v* L: _4 `
* `+ _- N/ z3 _- c7 N令t (n) 代表处理n 个点时,函数close 所需要的时间。当n<4时,t (n) 等于某个常数d。当n≥4时,需花费(n) 时间来完成以下工作:将点集划分为两个部分,两次递归调用后重构Y,淘汰距分割线很远的点,寻找更好的第三类点对。两次递归调用需分别耗时t (「n /2ù」和t (?n /2?).
3 R; s' z8 C; t% j! C5 S# Y
' }- {  Z0 i' A: q7 W7 i这个递归式与归并排序的递归式完全一样,其结果为t (n) = (nl o gn)。另外,函数c l o s e s t还需耗时(nl o gn)来完成如下额外工作:对X进行排序,创建Y和Z,对Y进行排序。因此分而治之最近点对求解算法的时间复杂性为(nl o gn)。</P>
zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2026-10-27 08:26 , Processed in 0.992708 second(s), 52 queries .

回顶部