我正在寻找O(n*logn)
算法来查找和打印n
个给定圈子的交叉点。每个圆圈由其中心和半径指定。
O(n 2 )算法在于检查中心之间的距离是否小于或等于半径的总和(被比较的两个圆的总和)。但是,我正在寻找一个更快的!
类似的问题是线段的交叉。我认为即使我的问题也可以使用line sweep algorithm来解决,但我无法弄清楚如何修改事件队列以防万一。
请注意以下角落情况。黑点表示事件点(根据用户Sneftel的解决方案,在箭头标记的圆圈下方不会打印)
答案 0 :(得分:3)
线扫描算法只会在遇到左极值(即(x-r, y)
)时将圆圈添加到列表中,并在遇到右极值时从列表中删除。在向列表中添加圆圈之前,请根据列表中已有的圆圈进行检查。因此,您的事件队列基本上是所有圆圈的左右极值,按x排序。 (请注意,您提前了解所有事件,因此在正常意义上它并非真正的“队列”。)
这也称为“扫除和修剪”。
答案 1 :(得分:2)
这是我根据用户Sneftel算法的修改找到的正确解决方案,该算法并非适用于所有情况。
图1:用有界框表示每个圆圈 现在使用扫描线方法,将扫描线平行移动到y轴,我们需要两个线段来表示每个圆的y范围,如图2所示。
完成后,问题将减少到以下几点:
这里有2个线段代表一个圆圈
扫描线状态可以保持为任何平衡的动态数据结构,如AVL树,跳过列表,红黑树,其插入/更新/删除/检索时间最多为O(logn)。
在这种情况下的比较函数将检查对应于相邻线段的两个圆是否相交(代替检查线段如在原始线扫描方法中相交以找出线段交叉点)。这可以在O(1)时间内完成,因为需要恒定的操作量
事件点数:4n(对于n个圆= = 2n个线段=> 4n个端点)
复杂度= O(4nlog(4n))= O(nlogn)