求绳子的最小长度

bey*_*uma 2 puzzle algorithm

我有以下编程问题:

给定一个整数长度数组作为输入,其中每个元素表示所需绳索的长度,求出原始绳索的最小长度,假设在每一步,你只能是绳索长度的一半,并且每根绳索的长度必须是一个整数。如果不存在这样的绳子,则输出 -1。

关于将长度为 x 的绳索“减半”的附加信息:

  • 如果 x 可被 2 整除,则生成的两条绳的长度为 x/2
  • 否则,生成的两条绳索的长度为 floor(x/2) 和天花板 (x/2)

例如,如果我需要 [3, 5, 2],那么我需要的最小绳索尺寸是 10,因为 '10' 可以分成 2 个 '5',剩下的 '5' 之一可以分成 '3'和'2'。然后,我最终会得到我所需要的 [3, 5, 2]。也允许以不需要的过多绳索结束。

我提供了一个功能,可以确定是否可以将特定长度的绳索分成所需的长度。

我最初想在搜索空间中进行某种二分搜索 [需要绳索的最大长度,___],但我不确定上限应该是多少。此外,我意识到这不一定有效,因为较长的绳索不一定能保证绳索可以分成所需的长度。

现在,我唯一的解决方案是线性搜索,但这似乎太慢了,我不确定会导致没有有效绳索的条件。

非常感谢任何指导!

Jon*_*ert 6

考虑任何所需的段长度m,并假设我们希望通过将绳索精确地减半来获得该段k。那么我们考虑的最短的绳子有 length (2^k)*m - 2^k + 1。如果我们将这条绳子切k成两半,每一步都丢弃较短的一半,那么我们最终会得到一段长度为m。我们考虑的最长的绳子有 length (2^k)*m + 2^k - 1。如果我们将这条绳子切k成两半,每一步都舍弃较长的那一半,那么我们最终也会得到一段长度为m

对于我们的长度m段,因此我们只需要考虑长度在[(2^k)*m - 2^k + 1, (2^k)*m + 2^k - 1]某个正整数区间内的绳索k。在最终绳索长度可以由 64 位无符号整数表示的合理假设下,k最多为 64。因此,使用我们上面的区间表示法,只有 64 个区间包含所有可能的绳索长度,可用于获得一个长度m段。

现在有趣的部分来了:假设n需要 lenghts 段m_1, m_2, ..., m_n。对于任何段m_i,我们正式定义第k-th 个候选区间为:

I(m_i, k) = [(2^k)*m_i - 2^k + 1, (2^k)*m_i + 2^k - 1]
Run Code Online (Sandbox Code Playgroud)

对于任何段m_i,让X(m_i)表示 64 个候选区间的并集I(m_i, 1), I(m_i, 2), ..., I(m_i, 64)。我们知道x解绳的长度必须包含在每个n集合中X(m_1), X(m_2), ..., X(m_n)。因此,我们将解的搜索空间缩小到所有 的交集X(m_i)

您可以通过首先生成64 * n区间来有效地迭代搜索空间中的所有值I(m_i, k),每个区间由您喜欢的编程语言中的一对整数表示(小心溢出!)。然后您使用快速整数排序器(例如基数排序)按它们的第一个分量(即通过它们的左间隔边界)对这些对进行排序。最后,迭代搜索空间只需要在排序的间隔上从左到右仔细扫描,始终检查所需的交集(我在这里故意省略一些技术细节)。

[7,7,8,14]最短绳索所需的段为例57

I(7, 1) = [13, 15]
I(7, 2) = [25, 31]
I(7, 3) = [49, 63]
I(7, 4) = [97, 127]
...

I(8, 1) = [15, 17]
I(8, 2) = [29, 35]
I(8, 3) = [57, 71]
I(8, 4) = [113, 143]
...

I(14, 1) = [27, 29]
I(14, 2) = [53, 59]
I(14, 3) = [105, 119]
...

Search Space: [29,29], [57,59], [113,119], ...

Run Code Online (Sandbox Code Playgroud)

如您所见,搜索空间明显变小了,以至于解实际上是搜索空间的第二小元素!

希望这可以帮助 ;)