让我们再试一次。
一些观察。
- 在已排序的元组数组中,第一个值始终为零。
- 数组的长度将始终与数组中存在的元组数一样长。
- 您希望这些是随机生成的。
- 元组按“排序”顺序生成。
根据这些规范,我们可以想出一个程序化的方法;
- 生成 2 个序列整数列表,一个用于选择,另一个用于种子。
- 对于种子列表中的每个数字,
[0, 1, 2, 3],随机追加和删除元素中尚不存在的数字。 [01, 13, 20, 32]
- 生成另一个序列整数列表,然后重复。
[012, 130, 203, 321]
但是,这不起作用。对于某些迭代,它会将自己退回到角落并且无法生成数字。比如[01, 13, 20, 32].. appending [3, 0, 1... crap, I'm stuck.
解决此问题的唯一方法是对整行进行 true 洗牌,然后重新洗牌直到适合。这可能需要相当长的时间,并且只会随着组数变长而变得更加痛苦。
所以,从程序上讲:
方案一:随机生成
- 用您的范围填充列表。 [0, 1, 2, 3]
- 创建另一个列表。 [0, 1, 2, 3]
- 随机播放列表。 [1, 0, 2, 3]
- 随机播放,直到找到适合的... [1, 2, 3, 0]
- 重复第三个元素。
使用此过程,虽然计算机可以非常快速地验证解决方案,但它不能非常快速地生成解决方案。然而,它只是生成真正随机答案的两种方法之一。
因此,最快的保证方法将使用验证过程,而不是生成过程。首先,生成所有可能的排列。
from itertools import permutations
n = 4
candidates = [i for i in permutations(xrange(n),3)]
那么。
方案二:随机验证
- 选择一个以 0 开头的三元组。
- 随机弹出一个不以 0 开头的三元组。
- 验证随机选取的三元组是否为中间解。
- 如果没有,请弹出另一个三元组。
- 如果是,请附加三元组,然后重新填充三元组队列。
- 重复 n 次。 # 或者直到你耗尽队列,此时重复 n 次自然变为 TRUE
下一个三元组的解在数学上保证在解集中,所以如果你让它自己耗尽,应该会出现一个随机解。这种方法的问题在于不能保证每个可能的结果都有相等的概率。
解决方案 3: 迭代验证
对于等概率结果,摆脱随机化,并生成每个可能的 3 元组组合,长 n 列表 - 并验证每个候选解决方案。
编写一个函数以验证候选解决方案列表以生成每个解决方案,然后从该列表中随机弹出一个解决方案。
from itertools import combinations
results = [verify(i) for i in combinations(candidates, n)]
# this is 10626 calls to verify for n=4, 5 million for n=5
# this is not an acceptable solution.
解决方案 1 或 3 都不是非常快,O(n**2),但根据您的标准,如果您想要一个真正随机的解决方案,它可能会尽可能快。解决方案 2 将保证是这三个中最快的,通常明显优于 1 或 3,解决方案 3 具有最稳定的结果。您选择哪种方法取决于您要对输出执行的操作。
之后:
最终,代码的速度将完全取决于您希望代码的随机程度。吐出满足您要求的元组系列的第一个(并且只有第一个)实例的算法可以运行得非常快,因为它只是按顺序攻击排列一次,它将在 O(n) 时间内运行.但是,它不会随机做任何事情......
另外,这里有一些用于验证(i)的快速代码。这是基于观察到两个元组在同一个索引中可能没有相同的数字。
def verify(t):
""" Verifies that a set of tuples satisfies the combinations without duplicates condition. """
zipt = zip(*t)
return all([len(i) == len(set(i)) for i in zipt])
n = 4 完整解决方案集
((0, 1, 2), (1, 0, 3), (2, 3, 0), (3, 2, 1))
((0, 1, 2), (1, 0, 3), (2, 3, 1), (3, 2, 0))
((0, 1, 2), (1, 2, 3), (2, 3, 0), (3, 0, 1))
((0, 1, 2), (1, 3, 0), (2, 0, 3), (3, 2, 1))
((0, 1, 3), (1, 0, 2), (2, 3, 0), (3, 2, 1))
((0, 1, 3), (1, 0, 2), (2, 3, 1), (3, 2, 0))
((0, 1, 3), (1, 2, 0), (2, 3, 1), (3, 0, 2))
((0, 1, 3), (1, 3, 2), (2, 0, 1), (3, 2, 0))
((0, 2, 1), (1, 0, 3), (2, 3, 0), (3, 1, 2))
((0, 2, 1), (1, 3, 0), (2, 0, 3), (3, 1, 2))
((0, 2, 1), (1, 3, 0), (2, 1, 3), (3, 0, 2))
((0, 2, 1), (1, 3, 2), (2, 0, 3), (3, 1, 0))
((0, 2, 3), (1, 0, 2), (2, 3, 1), (3, 1, 0))
((0, 2, 3), (1, 3, 0), (2, 0, 1), (3, 1, 2))
((0, 2, 3), (1, 3, 2), (2, 0, 1), (3, 1, 0))
((0, 2, 3), (1, 3, 2), (2, 1, 0), (3, 0, 1))
((0, 3, 1), (1, 0, 2), (2, 1, 3), (3, 2, 0))
((0, 3, 1), (1, 2, 0), (2, 0, 3), (3, 1, 2))
((0, 3, 1), (1, 2, 0), (2, 1, 3), (3, 0, 2))
((0, 3, 1), (1, 2, 3), (2, 1, 0), (3, 0, 2))
((0, 3, 2), (1, 0, 3), (2, 1, 0), (3, 2, 1))
((0, 3, 2), (1, 2, 0), (2, 1, 3), (3, 0, 1))
((0, 3, 2), (1, 2, 3), (2, 0, 1), (3, 1, 0))
((0, 3, 2), (1, 2, 3), (2, 1, 0), (3, 0, 1))
n = 5 有 552 个唯一解。这是前 20 个。
((0, 1, 2), (1, 0, 3), (2, 3, 4), (3, 4, 0), (4, 2, 1))
((0, 1, 2), (1, 0, 3), (2, 3, 4), (3, 4, 1), (4, 2, 0))
((0, 1, 2), (1, 0, 3), (2, 4, 0), (3, 2, 4), (4, 3, 1))
((0, 1, 2), (1, 0, 3), (2, 4, 1), (3, 2, 4), (4, 3, 0))
((0, 1, 2), (1, 0, 4), (2, 3, 0), (3, 4, 1), (4, 2, 3))
((0, 1, 2), (1, 0, 4), (2, 3, 1), (3, 4, 0), (4, 2, 3))
((0, 1, 2), (1, 0, 4), (2, 4, 3), (3, 2, 0), (4, 3, 1))
((0, 1, 2), (1, 0, 4), (2, 4, 3), (3, 2, 1), (4, 3, 0))
((0, 1, 2), (1, 2, 0), (2, 3, 4), (3, 4, 1), (4, 0, 3))
((0, 1, 2), (1, 2, 0), (2, 4, 3), (3, 0, 4), (4, 3, 1))
((0, 1, 2), (1, 2, 3), (2, 0, 4), (3, 4, 0), (4, 3, 1))
((0, 1, 2), (1, 2, 3), (2, 0, 4), (3, 4, 1), (4, 3, 0))
((0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 0), (4, 0, 1))
((0, 1, 2), (1, 2, 3), (2, 4, 0), (3, 0, 4), (4, 3, 1))
((0, 1, 2), (1, 2, 3), (2, 4, 1), (3, 0, 4), (4, 3, 0))
((0, 1, 2), (1, 2, 4), (2, 0, 3), (3, 4, 0), (4, 3, 1))
((0, 1, 2), (1, 2, 4), (2, 0, 3), (3, 4, 1), (4, 3, 0))
((0, 1, 2), (1, 2, 4), (2, 3, 0), (3, 4, 1), (4, 0, 3))
((0, 1, 2), (1, 2, 4), (2, 3, 1), (3, 4, 0), (4, 0, 3))
((0, 1, 2), (1, 2, 4), (2, 4, 3), (3, 0, 1), (4, 3, 0))
因此,您可以生成这样的解决方案,但这需要时间。如果您打算使用它,我会按原样缓存生成的解决方案,然后在您需要任何数字 n 时从它们中随机提取。顺便说一句,n=5 用了不到一分钟的时间来完成,蛮力的。由于解决方案是 O(n**2),我预计 n=6 需要一个多小时,n=7 需要一天。你可以得到一个真正的随机解决方案的唯一方法就是这样做。
编辑:不均匀分布的随机解:
以下是我在尝试解决此问题时编写的代码,它是解决方案 2 的实现。我想我会发布它,因为它是一个部分的、非均等分布的解决方案,并且 生成所有可能的解决方案,保证有足够的时间。
def seeder(n):
""" Randomly generates the first element in a solution. """
seed = [0]
a = range(1, n)
for i in range(1, 3):
seed.append(a.pop(random.randint(0,len(a)-1)))
return [seed]
def extend_seed(seed, n):
""" Semi-Randomly generates the next element in a solution. """
next_seed = [seed[-1][0] + 1]
candidates = range(0, n)
for i in range(1, 3):
c = candidates[:]
for s in next_seed:
c.remove(s)
for s in seed:
try:
c.remove(s[i])
except ValueError:
pass
next_seed.append(c.pop(random.randint(0,len(c)-1)))
seed.append(next_seed)
return seed
def combo(n):
""" Extends seed until exhausted.
Some random generations return results shorter than n. """
seed = seeder(n)
while True:
try:
extend_seed(seed, n)
except (ValueError, IndexError):
return seed
def combos(n):
""" Ensures that the final return is of length n. """
while True:
result = combo(n)
if len(result) == n:
return result