QQ登录

只需要一步,快速开始

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

距离最近的点对

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

823

主题

3

听众

4048

积分

我的地盘我做主

该用户从未签到

发帖功臣 元老勋章

跳转到指定楼层
1#
发表于 2004-10-4 05:18 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
<>给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。
2 E* d% F% ^- C6 j1 l+ E! f# }7 I
+ U0 P# q; O5 U. U1 f例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。
! K7 X* Q5 ~: f- T7 _0 ^( Z# T/ ~% u  }& \' J  P: e4 h/ j* R+ o
通过检查所有的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进行递归求解。
  w, |: q0 g/ h9 w1 x, ], H2 t; N5 Q
9 b4 X- X0 X! _/ Q/ e1 ^1 J2 I9 j& M* b
if (n较小) {用直接法寻找最近点对
+ |9 E$ L! a4 K* K. t* T/ _; r% w( u( ]  u4 v( D" K( P% l4 `
R e t u r n ; }' y. }; F& \3 u+ `. O; K
1 Y/ @) s. j! `* C. t( o
// n较大+ U6 o( F$ C8 i

/ a* ?3 g% H1 |1 P& |! p0 r- |将点集分成大致相等的两个部分A和B; E9 F$ i5 E1 j, U3 s
" ^: \3 I6 @7 C: X" ]0 Q% q$ G
确定A和B中的最近点对
) ^5 o' p. O  b% @* S
2 g$ p8 t& Y; ?4 W2 e5 g确定一点在A中、另一点在B中的最近点对1 R, g4 ]+ Q( V' K2 z3 @  h- Q

8 S% t/ |( n  _% R' a9 e3 P从上面得到的三对点中,找出距离最小的一对点4 {' u' l" v) i( H6 s* `

6 M$ w7 F  S: ^5 e% z图14-13 寻找最近的点对+ a  t) {8 f* I6 g# s
; U6 v, U& m1 c0 j, _
6 S# E; c  ^7 S* O6 `
为了确定第三种情况下的最近点对,需要采用一种不同的方法。这种方法取决于点集是如何被划分成A、B的。一个合理的划分方法是从xi(中间值)处划一条垂线,线左边的点属于A,线右边的点属于B。位于垂线上的点可在A和B之间分配,以便满足A、B的大小。
; ?# ~  I0 P% J* r+ Y$ w' z# _" O  C5 c+ z% f! @1 T0 y
例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。% L9 U7 ?0 `9 d# t. R

1 M% w& b$ y* B$ T4 {  G. E# v设是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)。
4 s! Q% v& j/ ?
% v- z, O8 ]+ a  p6 B例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) 是最近的点对。
0 l/ i1 B! p4 _1 J
* ~" s  l, i8 d  [# k. n为了确定一个距离更小的第三类点,RA 中的每个点最多只需和RB 中的6个点比较,如图1 4 - 1 6所示。0 L; i- E" c; G6 p/ Q. M
. a9 X+ J: f) }  C+ B- ?+ |
1. 选择数据结构$ V9 o$ X+ c% t% o7 c  ~% y
* n& r/ {0 @0 M
为了实现图1 4 - 1 3的分而治之算法,需要确定什么是“小问题”以及如何表示点。由于集合中少于两点时不存在最近点对,因此必须保证分解过程不会产生少于两点的点集。如果将少于四点的点集做为“小问题”,就可以避免产生少于两点的点集。" J" V6 Q8 V* x0 T9 b, S# i

( h' D  m- b  ~每个点可有三个参数:标号, x 坐标,y 坐标。假设标号为整数,每个点可用P o i n t l类(见程序1 4 - 8)来表示。为了便于按x 坐标对各个点排序,可重载操作符<=。归并排序程序如1 4 -3所示。3 I( p( J( @+ Y2 E; h2 v  B
, _( ?  ]# |  }1 |. m' E
程序14-8 点类1 z5 \& y- k/ K
6 d' w$ |  h# w8 X
class Point1 {
0 z# `+ e7 U, H$ U6 K4 F9 Y; @
1 n2 e3 d# C! |3 _4 h5 tfriend float dist(const Point1&amp;, const Point1&amp;);
6 ?. K+ s6 |  I0 G% `$ C8 I7 |$ J  G6 y1 O0 P
friend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);
+ t3 A/ k+ k9 u( u% `1 Q
& O8 Z7 B: U4 ofriend bool closest(Point1 *, int, Point1&amp;, Point1&amp;,float&amp;);" Q: L! t/ \! s3 I, e7 y% r- E* r3 L- ~

, M3 T  o2 m+ x5 d+ X- ]friend void main();, s7 y9 x# y7 M7 W

& I8 {6 J5 j6 Xp u b l i c :, ]6 \' b: C# C

% w1 O9 E) E" @6 k, Yint operator&lt;=(Point1 a) const
/ l- W$ u2 o6 Y9 L0 b4 z
7 [% l4 _  [' O$ t0 i% `2 |+ ^' o/ j{return (x &lt;= a.x);}7 x& Y7 m% q1 y" w7 _$ ~; s
( [. p" `) ~! t5 y, S7 o
p r i v a t e :
$ [; ?. ~5 v- V9 I9 ^$ ?1 t$ j+ S: Q( }7 B
int ID; // 点的编号+ w$ s( H5 o: v, A/ b8 {

) C) M, Y2 {/ i& A# H- P1 wfloat x, y; // 点坐标
' |/ e) W2 `& C: B" D
8 Q  d5 W: X: R4 }2 m' W$ K/ b7 K} ;
, ~, `& Q/ z, b) A% r' g
) d2 }  T2 a, E+ t5 Rclass Point2 {5 x) t! w: r$ k  n4 S. G6 D: z1 x( J
9 B. `9 y! y1 W$ H. l$ d4 q" y) D
friend float dist(const Point2&amp;, const Point2&amp;);
) k0 p9 j5 S# ]# n% D) z
$ v+ V1 \8 D' e  i  E! Rfriend void close(Point1 *, Point2 *, Point2 *, int, int, Point1&amp;, Point1&amp;, float&amp;);7 R+ L3 k& r6 s+ D8 Z: \' a

( y8 Y% v5 k5 N1 s* Vfriend bool closest(Point1 *, int, Point1&amp;, Point1&amp;, float&amp;);5 s& `: a8 u7 r6 R  |

2 O: B: g* P; o% s7 bfriend void main();* u7 r6 S1 p: c# Y; Z2 e' p- S+ A

! U! f0 V. q1 a4 Lp u b l i c :' k8 Q1 s: K* K" L# c8 p& t, D

% d$ ?! g# W! g+ hint operator&lt;=(Point2 a) const; L$ x& m- W( {# f9 }! k

) h4 F' i* K9 H{return (y &lt;= a.y);}
  y1 W+ W9 @$ j  _$ @$ H3 p4 Z4 v. g2 H3 S
p r i v a t e :, W6 q- z/ h; D  F* J6 H

- _1 w1 I8 z' C) `6 T1 Gint p; // 数组X中相同点的索引
$ q! R7 S) I1 `0 [- f* f& M  E/ W! Y$ @7 C1 {  z
float x, y; // 点坐标0 D$ C- g: f0 g
! \/ g( B5 N& n
} ;+ O, e" x" }! e$ e

% c1 f  W  @: w: j6 f所输入的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中的对应点。
. |# Y' k' E! Y7 R" I7 ?& l
7 }; k1 [& Y. a确定了必要的数据结构之后,再来看看所要产生的代码。首先定义一个模板函数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类的友元。
. K' F! E+ }& u7 L* H* R4 r
0 i0 `6 t' t8 f5 v' X$ b程序14-9 计算两点距离
, f6 ~* x+ a$ |8 {* B5 V" ~* R& s$ b8 X" h5 `3 i) {, C! ~) g
template<CLASS T>' X: ?9 k6 ]8 f* M7 e3 l. e( A
) t% s7 \6 K$ p0 l, W' E4 R. L
inline float dist(const T&amp; u, const T&amp; v)
  E) r* M' s1 t1 D& n. B
) g2 G: l$ D+ z0 d3 Y* [1 S{ / /计算点u 和v之间的距离
" X% q# S, g' ~8 ~5 H
6 w8 O, p' n; j9 B$ N9 W3 \+ h( T, zfloat dx = u.x-v. x ;
* d# P! e+ j0 |( o! g$ v) D* A7 l# c" y+ b7 R7 y- E! X: f' o
float dy = u.y-v. y ;
& ]: x% f. P1 ~5 {
  K5 }1 ]+ \: m) N2 ?$ h( ereturn sqrt(dx * dx + dy * dy);
: X: A; L' c7 {0 T. ]3 U  u3 u6 M! g$ Y# X: L
}% j6 }) I4 z+ x% |2 C% M& F% Z
# K- l1 L* O. b3 e9 z1 i0 S
如果点的数目少于两个,则函数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 ),该函数实际求解最近点对。3 X- `* u  A$ c4 ]2 _+ i7 h
8 N5 T' f8 Z! Q/ S' B( q0 y7 a+ q7 I
程序14-10 预处理及调用c l o s e
3 J! }! I* B9 X* w& H+ ^* _+ R5 R, P9 Z$ j5 \; _& \
bool closest(Point1 X[], int n, Point1&amp; a, Point1&amp; b, float&amp; d)+ w4 G# V6 M+ c- ?

) M* }: Z# _- O) x{// 在n &gt;= 2 个点中寻找最近点对8 p9 E- N# t3 W. S& m! R3 z

% M$ d  f4 T* V+ U( v// 如果少于2个点,则返回f a l s e
8 W- {! `1 |% [: H- F; ?0 R- o! U8 Z9 E' i& W1 f/ |
// 否则,在a 和b中返回距离最近的两个点* i  `/ R# T$ u- V
, j( {: p' x; ^9 o
if (n &lt; 2) return false;$ T% B% r+ E& |9 }5 |
( ~: B2 n0 \; n/ O
// 按x坐标排序
$ o% a( z- l8 F" H: h0 `0 Q  p" B2 x: N2 N' P, E! X4 ]3 ]3 m& ~
M e r g e S o r t ( X , n ) ;6 M3 p0 Q+ s6 N( [' }3 U
( m  V( y- ~+ n1 L
// 创建一个按y坐标排序的点数组  x; c$ p7 ]. }: K
6 s. W3 B2 U# Y; }
Point2 *Y = new Point2 [n];# o9 i8 q7 J0 [$ X% o; U; D& l
3 z# f& B% P: O6 g. c/ D6 A3 S
for (int i = 0; i &lt; n; i++) {7 M' o: f5 G# q) Q

4 {$ l6 _/ M0 {: m+ v# c// 将点i 从X 复制到Y8 D' a) {' O6 w5 n1 U9 B8 f; ^

5 |! `* B8 L" A2 Q& _/ K0 cY.p = i;
' _& J: Z. ^# W2 B! U+ K5 V& {
3 j. l+ P- Q/ T1 I9 ^" aY.x = X.x;. W7 m( k3 F1 n$ `+ Y
9 y- I8 H4 w: e- y9 o; ^9 s
Y.y = X.y;
  C9 b% v' i+ h
4 {( L& M  C: z5 T% w& y" b' Z5 |}( V* Q! v  |$ u. X, y
' i' S8 D" q) J. e$ {5 P0 Q2 W
M e r g e S o r t ( Y,n); // 按y坐标排序& J0 N# S/ ?. ^0 ?& S3 A

: H! ~, ^. p* C3 Y// 创建临时数组
2 o/ i' U, m+ k
. E% D9 @1 s% B$ `$ lPoint2 *Z = new Point2 [n];- ?9 q) l% d) \6 M( r

2 u9 Z8 ]$ K  @2 O; N9 j  Q// 寻找最近点对. @8 w( Z! r0 {3 ?: W' J3 Q# K% o
# N, S6 V3 o  r* R
c l o s e ( X , Y, Z , 0 , n - 1 , a , b , d ) ;
3 u& z  f) r9 z5 p- b2 ]% M; _( [3 Q/ f
// 删除数组并返回
: m) u$ M2 f: c- p$ h
& \6 y4 |0 o: w4 edelete [] Y;
3 g  C' ^& C7 M/ m/ M7 p$ v
5 r5 \: B+ \& X3 @delete [] Z;
: C+ o5 a! S, [/ T
! Y1 g  n# l1 Oreturn true;
7 f  a9 Y7 h" `' T$ V
% H! y. w' l8 Q# |  K}  d9 l" ^6 P9 o4 H; w3 ]) d- r

: `9 t  G  B! Z0 b. O程序1 4 - 11 计算最近点对
* K, ]- G% ~, H7 ~3 V' \% O; k0 d4 Q  `9 l9 q' Y( X7 H% n4 V
void close(Point1 X[], Point2 Y[], Point2 Z[], int l, int r, Point1&amp; a, Point1&amp; b, float&amp; d)
, L; z5 b5 R# T9 L3 m4 w; e6 @* R
{//X[l:r] 按x坐标排序( I6 F" U/ N8 h* T- o
; Z* u% p: a4 t0 f  z/ P0 u( q
//Y[l:r] 按y坐标排序6 y  G  \* Y$ f: m( E; r- g. z9 d
4 U9 ~3 g+ H3 k: R8 j7 G& z0 i
if (r-l == 1) {// 两个点
( ^/ w4 F3 G7 Q* M
  K- m9 w1 J% o8 v* F! y1 Y, da = X[l];! _2 D7 }/ p8 `2 {. d" @9 N, p
5 V6 }' R! S# j
b = X[r];
3 c- |$ X4 T- Y9 Q1 w5 n  [) G7 u6 R' z
d = dist(X[l], X[r]);9 O  _/ q% Y" Y

1 |$ ]9 ~9 c- k) v8 y5 q1 c( br e t u r n ; }
- d, ^/ p+ g0 p. r7 ]' `  J- ]$ y# k% L! T0 w/ d9 I. \
if (r-l == 2) {// 三个点
9 w, w; N9 l) t; U/ q* ]! a2 Q  I& K" b# J$ D6 j# |7 J
// 计算所有点对之间的距离( h* N9 k2 Q  S' p) l; S

$ x, L; @7 U7 g: S  _/ x, \float d1 = dist(X[l], X[l+1]);, ~- t" p8 Z' y

4 v" `. y' `; N$ s2 A, sfloat d2 = dist(X[l+1], X[r]);" D" m4 w; f8 p. X
4 D+ U- A7 S, C! t8 l
float d3 = dist(X[l], X[r]);
5 K2 u1 k- v3 _3 k) B4 \# d. ^  Y3 ^% n8 Y' s: \8 V# F
// 寻找最近点对
  x+ ~* |( g4 O: t3 G
+ _' [: f- h& B- r& K/ Pif (d1 &lt;= d2 &amp;&amp; d1 &lt;= d3) {) b* I6 n% c& O8 R, W+ A
8 |' ]9 {2 F6 G& u6 ]4 Q* z& ~9 q3 P
a = X[l];
, C: q; c$ `: s! p
  ]7 J. U8 v: l3 f' R0 H. Ob = X[l+1];# P9 C, D; w" Q2 E; j+ x

# D* Q4 Z* O* q; cd = d1;. h6 R# ~2 }! u  H
! z0 t, q7 y* m! K
r e t u r n ; }. }7 A, e8 g, a/ I' d
  m7 r( U: z- j% h
if (d2 &lt;= d3) {a = X[l+1];( \0 W( H$ ?+ L% ]
5 N8 [* I7 C+ H/ r- {9 H+ {* }. P
b = X[r];
  b0 E7 w# H0 D8 n. P6 `, z: x! g2 v+ @9 G# g0 {
d = d2;}
( S! M6 [% ]# N) q4 o) O& i& j# X! ]7 e7 l% q
else {a = X[l];9 }: v2 M# @- {) X3 O
! d$ `5 Z# \9 z" F8 F8 j0 O
b = X[r];- Q: `2 n# v2 {! g* g$ `
8 w: s7 `0 _& R4 H( q, @
d = d3;}1 Y& _: Q* N7 v5 o+ v

. C0 M) L, P0 D5 kr e t u r n ; }5 y; s% X/ L8 G
3 z, o- w6 ^( z) o+ z/ \& G
/ /多于三个点,划分为两部分
" f* f1 O5 K+ t/ J. ]2 F
) F6 E7 F3 y! P  I& t' w! e( F* [int m = (l+r)/2; // X[l:m] 在A中,余下的在B中( B) l: l! B/ G" j; _' v" M/ x: w% M

% t+ M( @  v% a- T9 I9 T0 l// 在Z[l:m] 和Z [ m + 1 : r ]中创建按y排序的表& p" S2 G7 F; O
, |7 U. w$ t( e) h8 c
int f = l, // Z[l:m]的游标
2 ^( g) }, B* I+ M9 S1 l9 {8 }6 ?  d9 y+ W, Q# K* G: O; Q. s1 k
g = m+1; // Z[m+1:r]的游标( O, M; ]8 n" t9 }- }* L3 ^
, ?- y& j; ]4 t' s+ J1 i
for (int i = l; i &lt;= r; i++): F& J% k" U# R- b3 V
+ V0 V+ Q& Z5 ?  v# \3 V' l
if (Y.p &gt; m) Z[g++] = Y;0 D2 |, x* T9 P( C# R' n% Y9 Q

) V% O7 G% V; X( V9 @7 \( @else Z[f++] = Y;, ^& p( n4 p; U+ d
% h  C; N( R! c$ Z  A
// 对以上两个部分进行求解7 _5 m) w! b- U$ v  C$ v# F: K( f
0 x- C2 f( F* R: f; K: q$ ]
c l o s e ( X , Z , Y, l , m , a , b , d ) ;2 s0 X- v7 n" G6 O

& G" ~. C9 I4 \4 _& Sfloat dr;
9 L9 m% {' V1 V% p; e$ a6 L1 o5 a+ ?+ l/ \/ v
Point1 ar, br;0 H, I; r4 X3 Q
& W9 T) L' C; J1 F
c l o s e ( X , Z , Y, m + 1 , r, a r, b r, d r ) ;, J& g% k( H/ R

0 |3 d; y: b$ R" D) n// (a,b) 是两者中较近的点对
& o' `- b" D5 ^8 c2 O* `  @! u  t1 F' `7 t! _2 ^4 {2 P3 M" P
if (dr &lt; d) {a = ar;
5 @7 x8 N( H! {! L; [7 K, o
' X# w2 w" {* `5 v: G  Gb = br;
8 \# U, h$ a! o5 T; L/ C' F# \2 `0 [! q* b
d = dr;}$ e* V0 ]5 {4 B
) v6 \, d: P! v, |' W/ t* a% n: |
M e r g e ( Z , Y,l,m,r);// 重构Y
; C1 w9 F+ @' X0 m  u( x( O6 F
* n$ E9 h" z6 z# i; G' T5 ^0 o/ /距离小于d的点放入Z
: a% o& M. ^9 C# l
3 D  g! W6 x9 Y1 pint k = l; // Z的游标) x( U7 I; b0 z$ c" j

2 M" g1 j: D* Hfor (i = l; i &lt;= r; i++)
/ p+ c7 E1 o1 I1 J7 h: S. Z2 i& A8 l- P+ @
if (fabs(Y[m].x - Y.x) &lt; d) Z[k++] = Y;
  G$ Q0 C. L1 @, Z7 {. }9 B7 V9 V3 a$ h. }2 y
// 通过检查Z [ l : k - 1 ]中的所有点对,寻找较近的点对9 g+ d4 ]* Z" N$ O2 f

; c* D% r8 f7 ifor (i = l; i &lt; k; i++){1 J, u% s/ w- T
1 G; o& W  b5 R# _- i+ K  h: M# h
for (int j = i+1; j &lt; k &amp;&amp; Z[j].y - Z.y &lt; d;
" @% G& H1 z, {! q
/ E1 b1 @. v0 ]% J: N0 Nj + + ) {/ A6 B2 {5 }) y. A/ @$ f/ _/ c% }
" \8 ~5 N/ C: c6 V# ^1 `6 f9 f
float dp = dist(Z, Z[j]);
2 ^. N+ e) V" ?5 y- I3 `, O$ F' ^. q7 J2 }5 j3 F
if (dp &lt; d) {// 较近的点对) H1 R  w( F2 U% V, S9 y8 g0 `
8 U5 b: h  o4 K2 G9 `) E! T9 e
d = dp;
% k. ^4 X. s5 i+ D2 ~+ G7 q" J+ V" R! i
a = X[Z.p];; M2 [4 V: l6 `7 y0 S
) @* Z' f/ J' X+ [! Z+ a
b = X[Z[j].p];}8 `- n, A0 }9 V' M7 `# [7 h) X
) N7 e1 i9 A) M" D
}3 G8 J" n# O) {5 c& s4 D
5 m* u8 e8 k4 y. X: w. P- M4 d
}9 Y% ~8 R$ N0 `) V3 a9 P! V; E9 p
, b' q0 N' @, o) Q
}; A) F0 m) v0 B/ f2 S; I2 W
2 L+ L+ S7 E0 y' V
函数c l o s e(见程序1 4 - 11)用来确定X[1:r] 中的最近点对。假定这些点按x 坐标排序。在Y [ 1 : r ]中对这些点按y 坐标排序。Z[ 1 : r ]用来存放中间结果。找到最近点对以后,将在a, b中返回最近点对,在d 中返回距离,数组Y被恢复为输入状态。函数并未修改数组X。
. V# t6 f0 f8 O' J: O
! D* m, L) A! d& d5 H0 c. d9 p首先考察“小问题”,即少于四个点的点集。因为分割过程不会产生少于两点的数组,因此只需要处理两点和三点的情形。对于这两种情形,可以尝试所有的可能性。当点数超过三个时,通过计算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 ]。9 I6 [& I6 M5 k% _# V
  i4 a0 J; a. Z
为实现图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,不管该点是在RA7 O5 `* l( ]! O8 {

, A; Y) q3 P4 B, E6 e, n. ]还是在RB中)与Z[j] 配对来实现,其中i<j 且Z [ j ] . y - Z [ i ] . y< 。对每一个Z [ i ],在2 × 区域内所检查的点如图1 4 - 1 7所示。由于在每个2 × 子区域内的点至少相距。因此每一个子区域中的点数不会超过四个,所以与Z [ i ]配对的点Z [ j ]最多有七个。
* b+ R. v, B9 [2 r1 u, h/ H# |1 X" T
2. 复杂性分析
7 H2 f% ]9 m! b
4 W4 G& F5 U1 x0 y3 D8 M令t (n) 代表处理n 个点时,函数close 所需要的时间。当n<4时,t (n) 等于某个常数d。当n≥4时,需花费(n) 时间来完成以下工作:将点集划分为两个部分,两次递归调用后重构Y,淘汰距分割线很远的点,寻找更好的第三类点对。两次递归调用需分别耗时t (「n /2ù」和t (?n /2?).7 w" U, I3 {$ X1 U% o
7 S3 [$ e1 I3 d) q9 Q, w
这个递归式与归并排序的递归式完全一样,其结果为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-4-20 06:14 , Processed in 0.453261 second(s), 52 queries .

回顶部