一些背景:我正在编写一个或多或少的蛮力搜索算法来解决我遇到的问题。为了做到这一点,我需要生成和评估所有可能性,以找出最好的。由于评估实际上需要一些时间,我希望生成尽可能少的解决方案,以完全覆盖我的搜索空间。此外,我能做的元素越多越好。对于任何数字 K,通常都有 K! 排列,并且对于高于 ~10 的数字很难生成它们。
真正的问题:搜索空间应该包含两个元素的所有排列(N 次 el1 和 M 次 el2,其中 K=M+N),具有以下限制:
- 它们必须是唯一的(即我只想要 [aabbb] 一次)
- 我不需要任何排列的反转(即,如果我有 [aab],我也不需要 [baa])
- 我认为排列是循环的,所以 [aab] = [aba] = [baa]
如果我能够做到这一点,那么可能性的数量将大大减少。由于 K 在理想情况下会很大,因此首先生成所有排列然后根据这些标准过滤它们是不可行的。我已经完成了第一个限制(见下文),它将 Matlab 的正常排列函数(perms)的数字从 2^K 减少到 K!/N!M!,这是一个巨大的胜利。第二个限制只会将可能性的数量减少一半(在最好的情况下),但我认为第三个也应该能够真正减少可能性的数量。
如果有人知道该怎么做,最好还知道如何计算有多少可能性,那将对我有很大帮助!我更喜欢解释,但代码也很好(我可以阅读类 C 语言、Java(Script)、Python、Ruby、Lisp/Scheme)。
对于有兴趣的人:这是仅获取我迄今为止拥有的唯一排列的算法:
function genPossibilities(n, m, e1, e2)
if n == 0
return array of m e2's
else
possibilities = genPossibilities(n-1, m, e1, e2)
for every possibility:
gain = number of new possibilities we'll get for this smaller possibility*
for i in max(0,(m+n-gain))
if possibility(i) is not e1
add possiblity with e1 inserted in position i
return new possibilities
- 如果你有 N-1 和 M 的所有排列,那么你可以通过将 e1 插入它们来使用它们来找到 N 和 M 的排列。你不能只是到处插入,因为那样你会得到重复。我不知道为什么会这样,但你可以计算出从旧的可能性中产生的新可能性的数量(我称之为“增益”)。对于第一个旧排列,这个数字从 M+1 开始,对于每个旧排列减一,直到它变为零,此时它又回到 M 等(仅当 M>=N 时才有效)。因此,如果您想计算 N=3 和 M=3 的排列,并且您有 N=2 和 M=3 的 10 个排列,它们的增益将是 [4 3 2 1 3 2 1 2 1 1]。