c++ - 寻找对的更有效方法

标签 c++ arrays algorithm

我最近遇到了一个问题,该问题要求找到好的圆对的数量。当通过连接第一个圆上的任意点 P1 和第二个圆上的 P2 可以获得给定的距离时,就形成了一对好的圆。我们有 N 个圆和 Q 个距离。接下来的 N 行包含圆心的坐标(XY)及其半径 R .之后,下一个Q 列出了要检查的距离。

以下约束适用:

2 ≤ N ≤ 103

1 ≤ Q ≤ 5⋅105

X,Y ≤ |2⋅105|

1 ≤ R ≤ 2⋅105

0 ≤ K ≤ 106

执行时间必须 < 1 秒。

这里,K 是要检查的距离。

删除了我的代码,因为它是正在进行的竞赛的一部分

我的代码只被部分接受,我花了几个小时试图为这个问题找到一个有效的算法。任何人都可以提供一个有效的方法来解决这个问题,以便解决 TLE 问题吗?

最佳答案

这是我可以从脑海中想到的一个可能的解决方案:

  • 遍历每对圆 (c1, c2) 并计算两个值 (P.S (c1, c2) 不同于 (c2, c1))
    1. 如果 c2 完全位于 c1 内,则忽略这对。
    2. Value1 - 圆 c1 和 c2 之间的最短距离,即 < em>它们的中心之间的距离 - r1 - r2 对于不相交的圆,0 对于相交的圆和 r 2 - dist - r1 对于 c1 位于 c2 内的情况。<
    3. Value2 - r1 应增加的最小值,以便 c1 完全吞没 c 2 使得它们根本不相交 - 这是它们中心之间的距离 + r2 - r1 用于不相交或相交的圆,dist + r2 用于休息。
  • 这个范围 [Value1, Value2] 定义了圆 c 的半径的数量1 应该增加,使其与 c2 相交,在我们的例子中由 K 定义。如果 K 属于范围 [Value1 , Value2], 那么我们可以保证在 c1 退出>1 和 c2 上的点 P2 使得它们之间的距离为 K。这是因为如果我们增加 c1< 的半径/sub> 在该范围内,它将与 c2 相交。
  • 上述操作的时间复杂度为 O(n2)。我们可以从所有可能的圆对中收集所有范围,并回答任何查询,我们只需要检查是否存在给定 K 所在的范围。
  • 为了方便查询,我们可以使用二叉索引树来存储我们的范围,其中我们在索引 Value1 处添加 +1,在索引处添加 -1 (Value2 + 1) 用于二叉索引树,然后对于每个查询,我们检查索引 K 上的读取是否 > 0。这使我们能够返回 O 中任何查询的答案(日志(K))。构建树的成本是 O(N2log(K)) - 包括形成所有圆对。
  • 我们还可以使用辅助数组而不是二叉索引树来回答 O(1) 中的查询,如果需要,我愿意讨论其范围。

至于辅助数组方法,初始化一个长度为 K 的数组,即 10^6,所有元素初始设置为 0。现在维护一个所有 Value1 的最小堆和另一个所有的最小堆值 Value2。 现在,

aux_array = [0, 0, ... ]
curVal = 0
for i in range(0, 10^6):
  while minHeapValue1.root() == i:
     curVal += 1
     minHeapValue1.rootPop()
  while minHeapValue2.root() == i:
     curVal -= 1
     minHeapValue2.rootPop()
  aux_array[i] = curVal

现在如果 aux_array[query_k_value] > 0,则表示有一个范围包含 query_k_value,否则不包含。

因此问题的总时间复杂度为 O(Qlog(K) + N2log(K))。

关于c++ - 寻找对的更有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52692702/

相关文章:

c++ - 具有专门构造函数的模板类

arrays - 根据为 x 设置的条件将 x-y 数据 reshape 为子数组

c++ - 堆数组分配而不是在堆栈上

c++ - 可修改的左值?

c++ - 为什么 vector 下标超出范围?

c++ - x509_store_add_cert 和 ssl_ctx_use_certificate 之间的区别?

c++ - 同步父子以从没有信号量的文件中读取

arrays - 在 perl 中为数组内的所有元素添加引号

Java词搜索算法

algorithm - 给定数字可以组成的最大数