【问题标题】:Rank and unrank Combination with constraintsrank 和 unrank 结合约束
【发布时间】:2020-01-27 13:35:14
【问题描述】:

我想使用元素距离约束对组合进行排名和取消排名。所选元素不能重复。

例如:

n := 10元素可供选择

k := 5 正在选择的元素

d := 3 2 个选定元素之间的最大距离

1,3,5,8,9 匹配约束

1,5,6,7,8 不匹配约束

如何对具有给定距离约束的组合进行排名,其中 1,2,3,4,5 小于 1,2,3,4,6 ?有没有办法在不计算排名较小的组合的情况下进行排名?

【问题讨论】:

  • “rank”和“unrank”是什么意思?
  • 排名意味着如果你按字典顺序对所有组合进行排序,那么最小的获得排名 0,第二小的排名 1,等等。to rank 表示 combination -> rankto unrank 表示 rank -> combination 但不计算所有其他组合。 rank 是组合的索引,如果所有都是按字典顺序排列的。
  • 没有选择的元素不能重复。

标签: arrays algorithm combinations combinatorics ranking


【解决方案1】:

您可以通过首先创建和填充一个二维数组来做到这一点,我将把它称为 NVT 来表示“有效尾部的数量”,以记录开始于的有效“尾部”的数量具有给定值的特定位置。例如,NVT[4][6] = 3,因为在第 4 位有 6 的组合可以以 3 种不同的方式结束:(…, 6, 7), (…, 6, 8) 和 (..., 6, 9)。

  • 要填充 NVT,请从 NVT[k][…] 开始,这只是一行全 1。然后回到之前的位置;例如,NVT[2][5] = NVT[3][6] + NVT[3][7] + NVT[3][8],因为从位置 #3 开始且值为 5 的“尾部”将由该 5 加上从位置 #4 开始且值为 6、7 或 8 的“尾部”组成。
  • 请注意,我们并不关心是否存在真正的有效方法来到达给定的尾部。例如,NVT[4][1] = 3 因为有效的尾部 (1, 2)、(1, 3) 和 (1, 4),即使没有 完成形式的组合(…、1、_)。

完成此操作后,您可以计算组合 C 的排名,如下所示:

  • 对于位置 #1,从位置 #1 开始计算所有有效尾部,其值小于 C[1]。例如,如果 C 以 3 开头,那么这将是 NVT[1][1] + NVT[1][2],表示以 1 或 2 开头的所有组合。
  • 然后对所有后续位置执行相同操作。这些将表示以与 C 相同的方式开始直到给定位置的组合,但在该位置具有较小的值。
  • 例如,如果 C 为 (1, 3, 5, 8, 9),则结果为
    0 +
    (NVT[2][1] + NVT[2][2]) +
    (NVT[3][1] + NVT[3][2] + NVT[3][3] + NVT [3][4]) +
    (NVT[4][1] + NVT[4][2] + NVT[4][3] + NVT [4][4] + NVT[4][5] + NVT[4][6] + NVT[ 4][7]) + (NVT[5][1] + NVT[5][2] + NVT[5][3] + NVT [5][4] + NVT[5][5] + NVT[5][6] + NVT[ 5][7] + NVT[5][8])。

相反,您可以找到具有给定等级 r 的组合 C,如下所示:

  • 为“剩余排名”创建一个临时变量rr,最初等于r
  • 要找到 C[1] — 位置 #1 中的值 — 从位置 #1 开始计算有效尾部,从可能的最小值(即 1)开始,一旦超过就停止rr。例如,由于 NVT[1][1] = 66 和 NVT[1][2] = 27,因此排名为 75 的组合必须以 2 开头(因为 75 ≥ 66 和 75 rr 中减去这个总和(在这种情况下留下 75 - 66 = 9)。
  • 然后对所有后续位置执行相同操作,确保牢记考虑到前一个位置的最小可能值。以 r = 75、C[1] = 2 和 rr = 9 继续我们的示例,我们知道 C em>[2] ≥ 3;由于 NVT[2][3] = 23 > rr,我们立即发现 C[2] = 3。

复杂性分析:

  • 空间:
    • NVT 需要 O(nk) 个空间。
    • 将组合返回为长度-k 数组本身需要 O(k) 个空间;但是如果我们一次返回一个值(通过调用回调或打印到控制台或其他方式),那么计算本身实际上并不依赖于这个数组,只需要 O( 1) 额外空间。
    • 除此之外,其他一切都可以在O(1) 空间中进行管理;我们不需要任何递归或临时数组或任何东西。
  • 时间:
    • 填充 NVT 需要 O(nkd) 时间。 (注意:如果d大于n,那么我们可以设置d等于n。)
    • 给定 NVT,计算给定组合的排名需要最坏情况 O(nk) 时间。
    • 给定 NVT,计算具有给定等级的组合需要最坏情况 O(nk) 时间。

实现说明:上面的细节有点繁琐;如果您没有具体的数据可以查看,那么很容易出现一个错误,或者混淆两个变量,或者诸如此类。由于您的示例只有 168 个有效组合,因此我建议您生成所有这些组合,以便您在调试时引用它们。


可能的额外优化:如果您希望 n 非常大,并且您希望对“排名”和“未排名”组合进行大量查询,那么您可能会发现创建第二个数组,我将调用 NVTLT 表示“小于的有效尾部数”,以记录从某个位置开始且值 小于 给定值。例如,NVTLT[3][5] = NVT[3][1] + NVT[3][2] + NVT[3][3] + NVT[3][4],或者如果您愿意,NVTLT[3][5] = NVTLT[3][4] + NVT[3][4]。 (您可以将其作为就地转换来完成,完全覆盖 NVT,因此它是一个 O(nk) 传递,没有额外的空间。 ( k 记录 n) 时间而不是 O(nk) 时间。请注意,此优化比上述更棘手,因此即使您打算执行此优化,我建议从上述开始,使其完美运行,然后才添加此优化。

【讨论】:

  • 能否请您显示 NVT 阵列。对我来说,它的 NVT[2][1]=27 但不是 NVT[1][2] 它的值为 50。谢谢
  • @TThoEinthausend:对于您问题中的示例(n = 10,k = 5,d = 3 ),NVT[[66, 50, 31, 15, 5, 1, 0, 0, 0, 0], [27, 26, 23, 17, 10, 4, 1, 0, 0, 0], [9, 9, 9, 9, 8, 6, 3, 1, 0, 0], [3, 3, 3, 3, 3, 3, 3, 2, 1, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]。所以你是正确的 NVT[2][1] = 27 和 NVT[1][2] = 50。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-01
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多