通常,我必须以某种半随机的方式生成数字序列,这意味着它不是完全随机的,而是必须具有其他一些属性。例如,我们需要一个1,2,3和4s的随机序列,但是没有数字必须连续重复三次。这些操作通常不是很复杂,但是我遇到了一个棘手的问题:我需要生成一个半随机序列,该序列有点长400多,由1,2,3和4s组成,每个数字必须出现相同的时间量(或者如果总和不能被四分之一整,而不是尽可能地将其整除),并且它们不能连续重复3次(所以1,3,4,4,4,4,2没问题)
我尝试方法:
创建一个具有所需长度和数量的列表;洗牌检查连续的数字是否正确,如果没有,请再次洗牌。
创建一个具有所需长度和数量的列表;生成所有排列并选择可以的排列;保存这些以供以后使用,并在需要时随机选择其中之一。
第一种方法运行了几分钟,然后生成了可以确定的任何序列,第二种方法产生了许多我的jupter笔记本放弃的排列。
这是第一个的python代码
from random import shuffle
v = []
for x in range(108):
v += [1,2,3,4]
shouldicontinue = 1
while shouldicontinue:
shuffle(v)
shouldicontinue = 0
for h in range(len(v)-1):
if v[h] == v[h+1] and v[h] == v[h+2]:
shouldicontinue = 1
break
else:
pass
和第二个
from random import shuffle
import itertools
v = []
for x in range(108):
v += [1,2,3,4]
good = []
for l in itertools.permutations(v):
notok = 0
for h in range(len(v)-1):
if v[h] == v[h+1] and v[h] == v[h+2]:
notok = 1
break
else:
pass
if not notok:
good.append(v)
我正在寻找一种有效解决此问题的方法,即:如果它实时运行,则不需要花一分钟的时间就可以在速度较慢的计算机上生成,也可以事先准备好以某种方式(如方法2的想法),它可以在几个小时的中等水平的计算机上准备好。
答案 0 :(得分:2)
在检查>400
长度列表的所有排列之前,Universe可能已经死亡。因此,您需要另一种方法。
在这里,我建议尝试将元素随机插入列表中,但是当插入会违反其中一项要求时,移至下一个索引。
根据情况循环遍历元素,从 1 到 4 ,应确保始终可以插入。
from itertools import cycle, islice
from random import randint
def has_repeated(target, n, lst):
"""A helper to check if insertion would break the max repetition requirement"""
count = 0
for el in lst:
count += el == target
if count == n:
return True
return False
def sequence(length, max_repeat, elements=(1, 2, 3, 4)):
# Iterator that will yield our elements in cycle
values = islice(cycle(elements), length)
seq = []
for value in values:
# Pick an insertion index at random
init_index = randint(0, len(seq))
# Loop over indices from that index until a legal position is found
for shift in range(len(seq) + 1):
index = init_index - shift
slice_around_index = seq[max(0, index - max_repeat):index + max_repeat]
# If the insertion would cause no forbidden subsequence, insert
if not has_repeated(value, max_repeat, slice_around_index):
seq.insert(index, value)
break
# This will likely never happen, except if a solution truly does not exist
else:
raise ValueError('failed to generate the sequence')
return seq
以下是一些示例输出,用于检查结果是否正确。
for _ in range(10):
print(sequence(25, 2))
[4, 1, 4, 1, 3, 2, 1, 2, 4, 1, 4, 2, 1, 2, 2, 4, 3, 3, 1, 4, 3, 1, 2, 3, 3]
[3, 1, 3, 2, 2, 4, 1, 2, 2, 4, 3, 4, 1, 3, 4, 3, 2, 4, 4, 1, 1, 2, 1, 1, 3]
[1, 3, 2, 4, 1, 3, 4, 4, 3, 2, 4, 1, 1, 3, 1, 2, 4, 2, 3, 1, 1, 2, 4, 3, 2]
[1, 3, 2, 4, 1, 2, 2, 1, 2, 3, 4, 3, 2, 4, 2, 4, 1, 1, 3, 1, 3, 4, 1, 4, 3]
[4, 1, 4, 4, 1, 1, 3, 1, 2, 2, 3, 2, 4, 2, 2, 3, 1, 3, 4, 3, 2, 1, 3, 1, 4]
[2, 3, 3, 1, 3, 3, 1, 2, 1, 2, 1, 2, 3, 4, 4, 1, 3, 4, 4, 2, 1, 1, 4, 4, 2]
[3, 2, 1, 4, 3, 2, 3, 1, 4, 1, 1, 2, 3, 3, 2, 2, 4, 1, 1, 2, 4, 1, 4, 3, 4]
[4, 4, 3, 1, 4, 1, 2, 2, 4, 4, 3, 2, 2, 3, 3, 1, 1, 2, 1, 1, 4, 1, 2, 3, 3]
[1, 4, 1, 4, 4, 2, 4, 1, 1, 2, 1, 2, 2, 3, 3, 2, 2, 3, 1, 4, 4, 3, 3, 1, 3]
[4, 3, 2, 1, 4, 1, 1, 2, 2, 3, 3, 1, 4, 4, 1, 3, 2, 3, 4, 2, 1, 1, 4, 2, 3]
在效率方面,生成具有相同要求的长度10,000的列表大约需要10毫秒。提示这对于大多数用途而言可能是足够有效的解决方案。
答案 1 :(得分:1)
我认为有可能(大约4 GB的内存和1分钟的预计算)生成比每个随机序列1秒更快的均匀分布的随机序列。
这个想法是为以下问题准备一个结果缓存:“有多少个正好为1s,b 2s,c 3s,d 4s的序列以特定数字的计数副本结尾?”
一旦有了此缓存,就可以计算满足约束条件的序列数(N),并可以通过选择介于1和N之间的随机数n并使用缓存生成n来随机生成一个序列第^个序列。
要在缓存中保存内存,您可以使用一些技巧:
这些技巧应该意味着缓存仅需要保存大约4000万个结果。