诀窍在于分割的方式,使得各个部分更小,并可独立处理。我们可以使用类似快速排序的枢轴将点分成两组。但要做到这一点比听起来困难得多,因为如果不正确地执行,这些组可能在特殊情况下不会缩小或不独立。
添加朋友: 需要评估的集合大小分别是1(什么都不需要做)、2(添加一对)和3(添加两对中的2,需要检查)
查找枢轴: 计算x和y的平均值,找到最接近它们的点p
分割:将点分成四组a,b,c和d,如下所示。 a,b是左下角和右上角的分区,c,d是左上角和右下角的分区,只保留更好的一个(如果a.size + b.size <= c.size + d.size,则取a,b)。这应该确保即使在特殊情况下,最大的不可分割集合的大小也为3(我不100%确定,但如果它应该更大,算法仍然保持不变,只需添加更多朋友的基本情况)。所有集合都包括枢轴和其他点,如下所示:集合a:x <= p.x || y < p.y,集合b:x > p.x || y >= p.y,集合c:x < p.x || y >= p.y,以及集合d:x >= p.x || y < p.y。我们应该得到两个集合,两个集合都具有约1/2到3/4的总点数,并且可以独立处理。因此,使用此算法可能会多次检测到一对朋友。
例如:
* * * * * * * * . * * *
* * * => * p * => * * . , . * * bottom-left top-right partition
* * * * * * * * * . * *
* * . * * . * * . . . .
* * . => * p . => * * . , * * . top-left bottom-right partition
* * * * * * * . . * * *
. . . . . . . . . . . .
* * . => * * . => * . . , . * * bottom-left top-right partition
* * * * p * * * * . * .
等等……简化:
a | b top-left bottom-right partition: 1st set: a, b, c, p; 2nd set: b, c, d, p.
- p -
c | d bottom-left top-right partition: 1st set: a, c, d, p; 2nd set: a, b, d, p.
这些组是独立的,因为ad和cb中的点不能成为朋友,p将永远挡在中间。左上到右下的分区将点a与d分开,而左下到右上的分区将点b与c分开。