【问题标题】:Find the permutations where no element stays in place找到没有元素留在原地的排列
【发布时间】:2010-11-04 16:27:37
【问题描述】:

我正在处理每个元素与其原始位置不同的排列。我想要一个给定{输入长度,行和数字}的算法,会给我输出数字。这是一个例子:

如果输入长度是4,那么0123的所有排列都是:

0123,0132,0213,0231,0312,0321,
1023,1032,1203,1230,1302,1320,
2013,2031,2103,2130,2301,2310,
3012,3021,3102,3120,3201,3210

没有数字在同一位置的排列(每个数字都移动了):

1032,1230,1302,
2031,2301,2310,
3012,3201,3210

编号从 0 开始,因此如果函数的输入是 {4,0,0},则输出应该是第 0(第一个)排列的第 0(最左边)数字。 1032的第一位是1。

如果输入是 {4,1,1} 那么输出是 1230 的第二个数字,即 2。

行号可能大于排列数。在这种情况下,取余数模排列数(在上述情况下,行模 9)。

用c语言会很棒。

(不是作业,是工作。Cuckoo hashing,如果你必须知道的话。我想随机选择我将在每个阶段进行的交换,看看当桌子的数量是大于两个。)

【问题讨论】:

  • 除非您在排列上定义部分顺序,否则这个问题确实没有有意义的答案。谁说 0123 必须在 0213 之前?
  • 好评论泰勒。我将排列从最小到最大排序,但我不关心行的顺序,只要输出仅是输入的函数并且每一行的可能性相同。
  • 如果这不是家庭作业,我很抱歉这样标记它。我再次删除了标签。我很确定,特别是因为你把它做成了社区维基。我很抱歉。
  • 所提出的问题似乎需要每次都即时计算所需的排列——O(n!) 工作,有点吓人(大约是 n!n 项排列的 1/e是“紊乱”,即没有固定点,当然乘法常数不会改变大 O 表示法)。是否可以让一个函数“准备数据”,采用输入长度参数,O(n!)一劳永逸地工作;和一个 O(1) 函数来提取所需的数字,因为数据已经准备好了?
  • 顺便说一句,一旦你知道没有固定点的排列被称为“错位”,你就可以在网上找到很多关于这个问题的资料。大多数解决方案涉及生成所有排列并清除非混乱,但也有直接的,例如mathforum.org/library/drmath/view/61957.html,基于将排列表示为循环并直接要求它们只有长度> 1的循环。还有discuss.joelonsoftware.com/default.asp?interview.11.746579.15,尽管讨论和代码还有很多不足之处;-)。

标签: permutation combinatorics


【解决方案1】:

Python 中的蛮力方法(您可以使用它来测试您的 C 实现):

#!/usr/bin/env python
from itertools import ifilter, islice, permutations

def f(length, row, digit):
    """
    >>> f(4, 0, 0)
    1
    >>> f(4, 1, 1)
    2
    """
    # 1. enumerate all permutations of range (range(3) -> [0,1,2], ..)
    # 2. filter out permutations that have digits inplace
    # 3. get n-th permutation (n -> row)
    # 4. get n-th digit of the permutation (n -> digit)
    return nth(ifilter(not_inplace, permutations(range(length))), row)[digit]

def not_inplace(indexes):
    """Return True if all indexes are not on their places.

    """
    return all(i != d for i, d in enumerate(indexes))

def nth(iterable, n, default=None):
    """Return the nth item or a default value.

    http://docs.python.org/library/itertools.html#recipes
    """
    return next(islice(iterable, n, None), default)

if __name__=="__main__":
    import doctest; doctest.testmod()

【讨论】:

  • not_inplace = lambda 索引:all(starmap(ne, enumerate(indexes)))
【解决方案2】:

为什么不只是构建一棵树并遍历它?

例如,如果您有数字0123,那么您知道最左边的数字只能来自set {1,2,3}。这将作为您树中的第一层。

那么,如果你沿着从 1 开始的路径下去,你只有三个选项,{0, 2, 3}。如果您在第一级中以 2 开头的路径,您只有两个选项{0,3}(因为您不能在左起第二个数字中使用 1 并且 2 已经使用过(您可以从您的选择列表))等。

在这种方法中要注意的是,如果您到达一个分支的末尾,而 3 是您唯一的选择,在这种情况下,您只需将其删除。

对于n > 10,生成所有排列然后过滤可能会出现问题。我认为建造树会显着减少这一点。

如果需要,您可以即时构建树。您可以通过遍历树的方式来定义您的顺序。

【讨论】:

    猜你喜欢
    • 2017-04-05
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多