【问题标题】:Getting i'th prefix without computing others获取第 i 个前缀而不计算其他前缀
【发布时间】:2013-01-05 18:49:52
【问题描述】:

我读过这个post,它与我遇到的问题非常接近,但无法概括它。 我正在尝试通过使用多个 CPU 搜索所有路径来解决旅行销售人员问题。 我需要的是一种将路径前缀编码为整数并将其分配给每个 CPU 的方法,以便它知道应该扫描哪些路径。 例如,如果城市数量是 10,一个可能的 3 前缀(假设前缀长度是固定的并且已知)是 4-10-3(有 10*9*8 个前缀),因此接收它的 CPU 将搜索所有以 4-10-3 开头的路径。 由于城市数量很大,我无法计算n!因此我不能使用上面的帖子。

【问题讨论】:

  • 我想我明白你想要做什么。我不明白你在哪一部分有困难。
  • @NPE 假设城市数量为 10,前缀大小为 3(固定)。所以有 10*9*8 个不同的前缀。我很难找到 [1,10*9*8] 范围内的数字和前缀之间的映射。

标签: algorithm math permutation


【解决方案1】:

排列为数字的标准表示使用Lehmer codes 表示在factorial number system 中。这个想法是n个元素的每个排列都可以映射到n个数字的序列,其中第一个在0到(n - 1)的范围内,第二个在0到(n - 2)的范围内等。然后,这个数字序列可以在阶乘数字系统中表示为单个整数。

我相信应该可以调整这个技巧来处理排列的前缀而不是整个排列。假设您有 n 个元素,并且想要选择其中 k 个的排列。为此,首先计算部分排列的 Lehmer 码。您将得到一个由 k 个数字组成的序列,而不是得到一个由 n 个数字组成的序列。例如,给定从 a b c d e f g 提取的部分排列 c a d,您的 Lehmer 代码将如下所示:

  • ca b c d e f g 的第二个(零索引)元素
  • aa b d e f g 的第零个(零索引)元素
  • db d e f g 的第一个(零索引)元素

所以 Lehmer 代码将是 (2, 0, 1)

一旦你有了这个 Lehmer 代码,你就可以尝试将它编码为一个整数。为此,您可以使用修改后的阶乘数字系统编码。具体来说,您可以尝试执行以下操作。如果你有 n 个元素并且想要其中 k 个的排列,那么最后一个元素总共会有 (n - k + 1) 个可能的选择。倒数第二个元素总共有 (n - k + 2) 个可能的选择,倒数第三个元素有 (n - k + 3) 个可能的选择,等等。因此,您可以使用 Lehmer代码并执行以下操作:

  1. 保持最后一位不变。
  2. 将倒数第二个元素乘以 (n - k + 1)。
  3. 将倒数第三个元素乘以 (n - k + 1)(n - k + 2) 4 ...
  4. 将第一个元素乘以 (n - k + 1)(n - k + 2)...(n - 1)
  5. 总结这些值。

这将为排列生成一个唯一的整数代码。

例如,我们的 Lehmer 代码是 (2, 0, 1),n = 7 和 k = 3。因此,我们将计算

1 + 0 × (7 - 3 + 1) + 2 × (7 - 3 + 2)(7 - 3 + 3)

= 1 + 2 × (5 × 6)

= 5 + 2 × 30

= 61

要反转此过程,您可以取整数并通过此过程向后运行它以恢复部分 Lehmer 代码。为此,首先将数字除以 (n - k + 1)(n - k + 2)...(n - 1) 以取回 Lehmer 代码的第一个数字。然后,将数字修改为 (n - k + 1)(n - k + 2)...(n - 1) 以去掉第一位。然后,将数字除以 (n - k + 1)(n - k + 2)...(n - 2) 得到 Lehmer 码的第二个数字,然后除以 (n - k + 1)( n - k + 2)...(n - 2) 去掉第二个数字。重复此操作,直到所有 Lehmer 码的数字都被重构。

例如,给定前缀 61、n = 7 和 k = 3,我们将从 61 除以 7 × 6 = 30 开始。这样得到 2,余数为 1。因此 Lehmer 码的第一个数字是 2 . 修改 30,我们得到数字 1。接下来,我们除以 6。这得到 0,余数为 1。因此第二个数字是 0。最后,我们读出剩余的数字,这给出了 Lehmer 的最后一个数字代码,1。我们已经恢复了我们的 Lehmer 代码(2, 0, 1),我们可以从中轻松地重构排列。

希望这会有所帮助!

【讨论】:

  • 可以,谢谢!您写道:“那么最后一个元素总共会有 (n - k + 1) 个可能的选择” - 为什么没有 n 个可能的选择?我错过了什么吗?
  • @Shmoopy- 选择前 k - 1 个元素后,您必须从剩余的 n - (k - 1) = n - k + 1 个元素中选择第 k 个元素.这有意义吗?
  • 哦,明白了,第一个有 (n-1),第二个有 (n-2),第 k 个有 (n-k+1)。
【解决方案2】:

这里最简单的方法是映射前缀而不将其视为排列的一部分。不要把前缀映射到[0,10*9*8-1],而是映射到[0,10*10*10-1],所以前缀0,4,5会映射到数字45,前缀 4,1,9 将映射到数字 419(当然,假设总共有 10 个城市)。

【讨论】:

  • 这是一个比我的方法更容易的解决方案。 :-) 我唯一担心的是,对于大集合的长前缀,这可能比更有效的映射更快地溢出整数。
  • 确实如此,但我认为这种技术不会溢出而最有效的技术不会溢出的情况不会很多。也就是说,你也许能挤进另一个城市,但我怀疑你能挤进更多。如果你遇到这个问题,你将不得不用另一种方式来解决它(不使用整数来编码整个前缀)
  • 这有点问题,因为它可能是模棱两可的。数字 12 可以解释为 1-2 或 12,因此您必须将它们分开,例如 -1。这将限制我可以支持的前缀大小。
  • 一点也不含糊。如果你有 10 个城市并且前缀包含 3 个城市,“12”只有“城市 0,城市 1,城市 2”和。没有其他意义。问题是另一方面 - 444 不是合法前缀,但这不是真正的问题,因为他是编码前缀的人。
猜你喜欢
  • 2013-04-02
  • 1970-01-01
  • 2021-05-25
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 2019-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多