QQ登录

只需要一步,快速开始

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

距离最近的点对

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:18 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。* o! y( @# ?6 @# v
4 i: ]9 ^3 y  n
例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。# K& |) f, _6 _

6 y& |5 ~1 }! D0 e# h3 S& d, t通过检查所有的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进行递归求解。  x7 k9 h% u4 [& T- P. |/ w/ \% b

+ B5 y! w! n3 r4 f- K( h9 I" K" \2 q$ m. z3 @$ ~0 h! D
if (n较小) {用直接法寻找最近点对
8 d" ~3 I3 x. y$ ?! I5 _0 o+ T
" o) Z0 Q4 O+ n/ I6 @& FR e t u r n ; }5 T( e& r# p0 [+ x4 n; J

% g0 w: V! H4 l/ ]' B- A& X; {  V: P+ y// n较大) x; Z6 \8 a: n$ ]5 B

+ d9 U: |+ r) w4 ]将点集分成大致相等的两个部分A和B+ N0 _+ f% O# i' B( g
( M  l0 p( J8 ^' ]" V2 e1 ~
确定A和B中的最近点对1 t. r7 g6 B1 ^; |

7 v  I- A6 O& `6 F$ ?确定一点在A中、另一点在B中的最近点对) V) `( n5 |, Y8 Q
/ e1 z- ], H! ~: L0 a# q
从上面得到的三对点中,找出距离最小的一对点
5 P# w: U! _1 {
/ C3 f* F( J" t- D2 P/ {1 j图14-13 寻找最近的点对; f+ \  n3 d! D3 L. u

- s4 q( ^. ]9 i# a" F& C
, k7 M0 l* ^  c( i8 {为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。9 o' o" V4 o) T& k  U* E
$ I! {. ?& @( p% ~" 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。
& S' m0 h/ U( e  {: E0 T) W) b: }+ q, j, K- w
设是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)。
( p3 i; B6 j  {' P  u! d; m: f( Q
: `+ o3 m/ m" v7 L% b; D! A8 S例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) 是最近的点对。# n6 h# T' |6 H$ Z' i5 W% l4 ~
( u( f; v/ K7 S& N) X
为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。
6 t+ x$ C9 [% h2 j! w& B, @. g5 u; B& r5 T/ {! r
1. 选择数据结构2 q1 M8 `" O) d0 v& a' B) y, M
: W& w: @3 r' y$ `* k6 s8 a  ]
为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。# E. e# L7 {5 s6 q

  T, @6 V* d; o, `3 q8 \% e- f每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。" v5 ~6 z8 N8 X/ F

! Z; h3 {. Z4 ?. e. r程序14-8 点类
, U7 Q" T  \4 o
, a% c+ m; H. Pclass Point1 {$ q1 ~& b" ]" p5 A% o

! p  N8 `2 ~( i# A6 T! ?0 W1 ufriend float dist(const Point1&amp;, const Point1&amp;);& c* U' }( Z0 w9 Q. X9 b( E$ F

8 _6 W/ T! I5 ~) ifriend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
% N* v, S/ v) `8 P: {6 q4 F. o5 f) J( Q* R
friend bool closest(Point1 *, int, Point1&amp;, Point1&amp;,float&amp;);' k; x" `# s* x0 q# F; ]4 S% m; T
# Q+ j! p( Z& l+ @) \! f
friend void main();
3 x  n, l( V9 ]
  t9 S, ]) V7 N$ l+ {! Np u b l i c :
0 l+ o2 u: q7 K2 ?. `' U7 a- Y
% ]- w6 \- \. X. V! K4 A& Cint operator&lt;=(Point1 a) const
+ u, F, U6 J8 q, L$ G( o. G
7 }/ G4 L; I: L0 ]{return (x &lt;= a.x);}: B6 y+ J+ H6 g: ^# r$ B) E9 G+ \# R
% E9 x1 F' j9 r+ T. g% `
p r i v a t e :3 F' Z* i% X+ {4 ?; c* F0 m
4 G2 X3 X0 d) M* D) c2 @! P7 G( X
int ID; // 点的编号8 l. K- f/ @+ W+ }
. J# _, J7 w. {" g  N" J, U" n
float x, y; // 点坐标/ l3 F9 s# A" y) s( ~3 @: K4 s
, x& }" a7 h9 T( D& e0 _
} ;
& x* R: R0 z. m3 l. t9 r$ d; G% s1 h' F) E* b2 D1 n
class Point2 {2 H2 d+ w& N8 N% h( c
% J' t" P1 P3 ?: I& |+ z
friend float dist(const Point2&amp;, const Point2&amp;);' Z9 T0 T6 Y8 O  ^

8 M4 W, A5 r$ y. W# D3 @friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
. u5 o! |: H9 X  k
, u5 K0 L0 y% g/ y0 J: H! Yfriend bool closest(Point1 *, int, Point1&amp;, Point1&amp;, float&amp;);9 {5 v4 T. X; E) x

/ O, {5 b1 S$ mfriend void main();
' J9 l# |$ A8 [, X# u0 T) S/ M1 Z0 Z
p u b l i c :
8 D1 m2 d7 [: J7 F6 c$ E1 ]; c# ?# e1 K* |. G; z
int operator&lt;=(Point2 a) const
0 S) o& L, `1 `) a; [1 k6 P+ O2 i5 i2 s
{return (y &lt;= a.y);}% _5 a; D) R4 W- C, g% l

. H) T7 ?8 P1 h8 v" D" h4 np r i v a t e :
1 d, `" p- z& ~) Y( e) ]8 R/ K. ^
: O1 O2 F$ z* g4 b1 Lint p; // 数组X中相同点的索引
* G9 f5 _( x0 L# O4 y, s, E2 F: g. |
float x, y; // 点坐标5 S; ]) [* @& N; C* ?
! ~9 U/ X* M- u& Y! E# P: d
} ;
4 g- |/ A  i' v( k  i. |. w  I! R9 _% p" P& S& {4 a
所输入的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中的对应点。
. k+ s9 Y) Z% W. v. d& d
/ r' _' r& Y% `( u* S' C" Z确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。
# E) ~1 M& L% s/ [9 o( w4 ~
7 r* }' v  W5 [9 L9 F程序14-9 计算两点距离7 W" r8 M9 L- j( t5 U4 o0 \

/ S4 N6 B1 h6 z' C3 ~template<CLASS T># T+ e& b1 R- j. c: m

1 T$ @. h7 w' V& q9 O2 ]inline float dist(const T&amp; u, const T&amp; v); F7 R- \& E+ M  g' g
0 A( k3 M/ \5 z4 \  R6 p
{ / /计算点u 和v之间的距离7 i0 c" }! Z' Y# E9 Z" T9 }/ y
/ M4 Y- a% M* z7 m/ T: [3 ?0 t
float dx = u.x-v. x ;9 c1 T+ j# b5 q8 z2 S2 L! c
  {' F: d% e# D: L
float dy = u.y-v. y ;
0 V, ~* H. B4 }, f2 w( I+ s: h+ \) v' t$ {2 ~3 @' g6 g; B
return sqrt(dx * dx + dy * dy);  s1 K, H$ X3 n( N& r% @

8 J- p/ M1 a: g+ w}) t& v9 |1 L1 V6 H  a, U& C( `

+ C& \* q  o4 W  z  |9 |( ?0 Q9 B; o如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。
  k+ {6 j3 Q- \% h! p! s. r) U9 H7 ?
程序14-10 预处理及调用c l o s e  w' `5 q8 W+ {; @

1 I* p9 b( }' f8 s5 W3 i6 y) A0 `3 wbool closest(Point1 X[], int n, Point1&amp; a, Point1&amp; b, float&amp; d)
# ?5 d) A4 o" G" `% _  Z/ y* `  w* v" x1 y; j
{// 在n &gt;= 2 个点中寻找最近点对4 F& u) @4 l! m+ B

, R) v$ B0 s& P+ V9 i// 如果少于2个点,则返回f a l s e
1 Z1 @% R+ w4 G& O" O, S3 N' F9 [3 A: |/ M, l! c" X
// 否则,在a 和b中返回距离最近的两个点; b0 M- h* e- `' E3 _; e" j& W4 V1 y
& F$ }. T% f* o* G4 L  W4 u
if (n &lt; 2) return false;
  p3 |- X& T& [- W
8 Q4 u8 Z& k' Z' y# p$ {// 按x坐标排序
4 A! r2 |2 W$ P+ I4 B0 I6 K; t6 ]7 r- I6 F* M6 i$ ?
M e r g e S o r t ( X , n ) ;
$ I2 |2 h7 s0 c$ i2 p6 @4 R/ A  u. k: A- }' {6 ?* N( ~, m% ?7 ^6 m
// 创建一个按y坐标排序的点数组
) V1 j6 t8 Y. e" Q6 w) c0 z. G: x4 q1 u. Y1 l/ g3 A( y# G$ z* g
Point2 *Y = new Point2 [n];
. r6 V4 w3 D' K
5 p+ R* s* d( Y; R$ tfor (int i = 0; i &lt; n; i++) {
  J# E: l" d/ ~+ E( ]7 L/ X
5 V4 V3 _, r  G: j# o. K  e. b5 Z# m// 将点i 从X 复制到Y: `4 |0 [; X' ~4 i' ^% ]: D

4 C! g& O! ?8 k0 Y8 zY.p = i;* B8 @" y) [6 w

+ M. g" `( |# A+ l1 m/ LY.x = X.x;  e6 ^0 C, Q& H; Y# o* ?' o# k
7 B: h+ C1 s2 I3 f) x1 y
Y.y = X.y;
9 G' L( r/ D0 \; k, z. _+ l# q$ ~0 s7 s
1 f, H4 Q7 ^) D& ?}' i8 c, ^2 `0 N3 b- P/ u* @, R

+ @' A* _$ p) y2 j# a  A3 I3 iM e r g e S o r t ( Y,n); // 按y坐标排序, w! P" C; G2 C& L' X: w: M

5 W/ D1 u, N- w9 w+ U6 C// 创建临时数组  o' i; {  }( d& {/ S6 D; {9 n
8 L! o" @+ ^1 Q% b
Point2 *Z = new Point2 [n];
3 W) A) s9 U8 T+ h1 x! }
* L: b& C& @7 g% j7 e/ T// 寻找最近点对
: H5 B& @- @% q$ N
3 @" B: Z1 s# Q  Dc l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ;) [: X  W) [6 ^9 S

  l' `1 Y& N7 l6 q- P// 删除数组并返回
& n; T* D& t$ @$ R" B2 D
6 f5 M6 R/ T* h8 Q, E5 H5 F! Sdelete [] Y;+ s4 ?+ {6 T6 ^: i, z# c
) _$ Y- t# B2 [2 Y/ x$ ~' U1 D: ]
delete [] Z;
% l0 i" x- T0 U2 J9 b6 s
2 J& Z& o* E7 Q. B* u* zreturn true;; c2 d4 ?# c# c1 N! Q, }0 @
1 v! m. f. \9 g& l( d
}
% ]% }3 W! X: p" F6 B5 ?' r+ F) N$ i& t& R
程序1 4 - 11 计算最近点对
/ `7 o6 L# [* v0 v
; M+ X! m  P3 A$ K5 Jvoid close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1&amp; a, Point1&amp; b, float&amp; d)9 x9 c2 }. o  N; _  {( n4 u

; L# S, c- [6 n, L$ N, ?2 i3 s{//X[l:r] 按x坐标排序
) B, Z' H9 k3 q! j& p
4 i3 P; r0 H- S+ r6 ~//Y[l:r] 按y坐标排序
4 s5 K4 r+ J: O" O1 @" B) [4 M1 [8 p% ]1 G0 V
if (r-l == 1) {// 两个点& A# `& T( ~/ r; D- u/ ^' d' c; X2 t
  K: @; W! ?  X3 d6 q2 L2 Y: n, q
a = X[l];" J6 V0 s- r5 S
: E* u0 L1 G; i# Q+ t1 {& H' |
b = X[r];( T  x& A1 s% D5 R3 T

+ C8 ^$ E5 j& v1 a+ Id = dist(X[l], X[r]);9 R( y6 i% \; v$ Z2 c
$ c5 }4 l/ i6 j2 B
r e t u r n ; }
% [6 }/ E. d' V  q9 w1 L) N# ~- {$ F3 g. p: O
if (r-l == 2) {// 三个点
" @2 D$ H, L5 h3 [; _" x, J& L
. x1 f* v- V5 C* Q/ h$ C' S% p// 计算所有点对之间的距离9 T, G! K# C6 T" O

% O. ?- p! w! Sfloat d1 = dist(X[l], X[l+1]);, i7 A- g# H/ n  ~3 a/ M8 k) r; _( Q% Q
- E% _% w4 j( K. T' f
float d2 = dist(X[l+1], X[r]);
$ n# s3 b6 ?2 R* T+ g( _
. `; f. w! v8 p8 g; S* J2 Zfloat d3 = dist(X[l], X[r]);( E$ I# G: x2 i
2 @- O; K% o6 N! ]* C& e
// 寻找最近点对& d% G. p2 E- q% U8 q) o- q

3 H) L+ ^( }( u5 bif (d1 &lt;= d2 &amp;&amp; d1 &lt;= d3) {
, V6 k& ^+ r. c9 F; t" t) O
/ b# I- C' I5 z7 d/ C- Ia = X[l];
9 a+ ?# ], t  r3 D0 z: b3 |" y+ `' X) j: H' E
b = X[l+1];8 F- B& k  }2 v8 W" S

: O  W+ r6 w1 D  @- zd = d1;
2 G& t% A/ E1 n. w& g2 W0 E% h' F2 ]6 b. H) J" ^
r e t u r n ; }: r% J) b8 L  V2 `" v% S
2 L, _% Z2 c3 B1 Y* J
if (d2 &lt;= d3) {a = X[l+1];
& c+ A' `; N5 Y; f* `2 J& N% [$ ]) G. r# J, P: J. X
b = X[r];5 J3 I6 I" h+ w# t4 B& ^, F" K& i
: _6 {4 L* T0 `
d = d2;}
: V; T7 U$ S, o) ]% R8 a& y
2 f  N% N0 R2 B" Y- I' c; t+ b0 E! `else {a = X[l];
5 |/ {- k! g+ R$ Y' m9 N0 V6 L
/ W0 J+ j1 k, Y" I, q2 H: I$ ab = X[r];0 j2 s  _+ }8 f- Z/ {! R" K1 Y
$ K% v1 B  d6 P: {, E2 _
d = d3;}6 T0 d! w# n8 R4 `8 _* [

# _% K4 J+ ?& }  _( kr e t u r n ; }
/ _) ^2 ?2 K1 K% C  N! @, \
4 s/ P$ k; p2 O/ /多于三个点,划分为两部分
; C: Y$ `+ }! C3 a  G0 Y: r4 D$ ^" |4 Q
int m = (l+r)/2; // X[l:m] 在A中,余下的在B中, V6 H+ ]$ Y" r, b6 O

2 |8 H( ^- }# t6 Y, {// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表
# c/ B; e  E7 I, O* d
& U; Z. S+ @- k, wint f = l, // Z[l:m]的游标
$ G* |+ S6 i; H3 q/ x  e7 w- C3 s
4 D9 m9 V( z4 T/ y% rg = m+1; // Z[m+1:r]的游标: j& V/ w, R5 T, I& U
: ~$ H; e" E0 {# o1 r# c
for (int i = l; i &lt;= r; i++)4 q7 c) Y$ i' W" K: X: ]' y  y
* h) m0 t6 H9 K0 i0 h
if (Y.p &gt; m) Z[g++] = Y;7 [- `3 L; X8 ^; R8 q

& A# `6 f9 c# X/ o8 ~4 `" melse Z[f++] = Y;
- [9 S; d: U6 l0 Y" G1 f( [0 c. `2 |. K+ _( `4 v% w
// 对以上两个部分进行求解
5 b# A% z2 X7 M5 F
$ c! z2 T0 V5 p9 S1 Zc l o s e ( X , Z , Y, l , m , a , b , d ) ;
8 h( [+ W( \, M; P1 t6 q! Y8 y# D' b3 L+ @3 c( Q& k
float dr;3 F* p' p# l7 P8 r7 H. S% ^

4 Q: W/ ]6 D+ yPoint1 ar, br;7 Z- K9 V/ H3 [2 A5 O& T) S

5 ~/ W7 C, v) W4 ?7 Q; [% Kc l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;3 }' n' j& ~9 G% b
( K, K2 E! W( L* D. V: G
// (a,b) 是两者中较近的点对( f$ j, R2 s1 ~* f7 D0 j

) G, [: F4 w" k7 kif (dr &lt; d) {a = ar;1 d0 m9 S* e/ V+ I; U

8 T3 \$ w9 [$ d* V# o- tb = br;; y- m+ M4 S' K* ~+ ^

6 y0 R+ m! W9 F' I1 id = dr;}) l5 y: D! x0 C$ H" Q! c) j
4 r6 x8 I6 b* l# N7 W9 W( a- ?
M e r g e ( Z , Y,l,m,r);// 重构Y
/ a" P- o- ?/ Q5 t! O4 e. d+ Z* X$ ?3 h% J
/ /距离小于d的点放入Z
  `( T" }6 [9 h, K3 D$ x
* D, [9 t/ s5 K) H% gint k = l; // Z的游标+ Y  R  X) q6 _
+ G$ Z; n1 R: m' m1 D0 m; P5 d
for (i = l; i &lt;= r; i++)
+ u- J, h- O4 O) Z7 g3 S! |9 `5 e5 f; y
if (fabs(Y[m].x - Y.x) &lt; d) Z[k++] = Y;
% M$ ~# M9 ]1 R' {) ~2 d. O" W& g" G" Z
// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对
/ _  b. n- V3 Q. l
% @# i& z" S4 S% U6 Q% Afor (i = l; i &lt; k; i++){
* x1 I! o3 n4 X, k# T& K/ W7 j( W+ k' r: F' t7 q, }
for (int j = i+1; j &lt; k &amp;&amp; Z[j].y - Z.y &lt; d;0 m1 c" ^4 ?- g
4 R/ G$ R, z6 x: u  ~, h8 e" [' L
j + + ) {
( }5 ^+ ~1 I9 e9 l* \3 u
) k, {( Z8 f$ X, Lfloat dp = dist(Z, Z[j]);
2 O9 h0 F$ X6 F/ E) O5 S9 Y
3 c' }1 _) x) j0 iif (dp &lt; d) {// 较近的点对% x4 C, P* ?4 P5 X: z& t

5 ~# h9 w3 V7 ]& u8 A. d# O+ l: ]d = dp;
) ?! Y2 Z4 k7 N. e  u, B# r5 b
$ {, b/ w# q0 v$ \4 Ga = X[Z.p];8 |2 q- p) L' A( s- [5 O0 t4 H: w

1 H' s' E+ V* n+ @5 Nb = X[Z[j].p];}
+ j( s8 b9 ^- ~1 M0 F, z
3 f6 V5 Q+ P6 Y}/ M+ Y4 w6 t9 S8 B" k+ Z

# Z( E9 y) U7 u5 X" r8 X}
; t1 B. ~/ p! u+ z, z' M' ]8 h0 M/ S- k) [& B. p+ X% r% [
}; u+ J1 v" }& s$ x( v6 ]

: f& C2 F# V% n$ K2 g8 D; U函数c l o s e(见程序1 4 - 11)用来确定X[1:r] 中的最近点对。假定这些点按x 坐标排序。在Y [ 1 : r ]中对这些点按y 坐标排序。Z[ 1 : r ]用来存放中间结果。找到最近点对以后,将在a, b中返回最近点对,在d 中返回距离,数组Y被恢复为输入状态。函数并未修改数组X。
' h. D* e1 o5 R  L  {
3 c- s1 i. L6 v) Q) U首先考察“小问题”,即少于四个点的点集。因为分割过程不会产生少于两点的数组,因此只需要处理两点和三点的情形。对于这两种情形,可以尝试所有的可能性。当点数超过三个时,通过计算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 ]。
1 |$ f! _1 n' h! t7 d0 H
$ t& q, V+ t* g7 o- s为实现图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,不管该点是在RA1 W" a* y  c* O9 n

4 }/ ]5 ~# p! N& j" L还是在RB中)与Z[j] 配对来实现,其中i<j 且Z [ j ] . y - Z [ i ] . y< 。对每一个Z [ i ],在2 × 区域内所检查的点如图1 4 - 1 7所示。由于在每个2 × 子区域内的点至少相距。因此每一个子区域中的点数不会超过四个,所以与Z [ i ]配对的点Z [ j ]最多有七个。
3 T/ w; Z! s! Y- k( U" Y+ v. M% ~7 L. J$ j) u" H& H/ b+ p
2. 复杂性分析
( ^1 u5 T- U2 O  K$ @3 o
* k8 A7 e. `- r2 X0 Q; f6 J令t (n) 代表处理n 个点时,函数close 所需要的时间。当n<4时,t (n) 等于某个常数d。当n≥4时,需花费(n) 时间来完成以下工作:将点集划分为两个部分,两次递归调用后重构Y,淘汰距分割线很远的点,寻找更好的第三类点对。两次递归调用需分别耗时t (「n /2ù」和t (?n /2?).
8 l7 a9 a& `! E/ j; I! I* H/ u4 ^0 L
这个递归式与归并排序的递归式完全一样,其结果为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-24 07:56 , Processed in 0.806601 second(s), 51 queries .

回顶部