Подход 1 - Наивная случайная генерация
Это неэффективный, но простой подход - взять z*2
случайные целые числа из range(a, b)
, отсортировать их, объединить их в пару и проверить, все ли интервалы превышают или равно w
. Повторите это n
раз.
Обратите внимание, что это будет неэффективно, когда z*w
близко к len(range(a, b))
. Я подумал об уменьшении этого, добавив вспомогательную функцию для генерации случайного интервала nth
, который позволял бы создавать оставшиеся интервалы z-n
- путем выбора индексов из range(a, b-w*(z-n))
, но это сталкивается с проблемой, что интервалы выбираются первыми будет смещен в сторону того, чтобы быть дольше.
Код:
def list_to_pairs(l):
return [l[i:i+2] for i in range(0, len(l), 2)]
def f(z, w, a, b):
intervals = [(0,0)]
while not all(x[1]-x[0] >= w for x in intervals):
intervals = list_to_pairs(sorted(random.sample(range(a, b), z*2)))
return intervals
def get_lists(n, z, w, a, b):
return [f(z, w, a, b) for _ in range(n)]
Выход:
>>> get_lists(4, 3, 5, 0, 100)
[[[0, 17], [22, 46], [62, 98]],
[[10, 32], [61, 66], [72, 81]],
[[2, 31], [63, 68], [77, 87]],
[[5, 20], [34, 55], [58, 86]]]
Подход 2
@ Питер О. обрисовал в общих чертах лучший алгоритм , который не основан на случайных интервалах выбора, которые я кодировал ниже с несколькими незначительными изменениями логики c.
Код:
def positive_integers_with_sum(n, total):
ls = [0]
rv = []
while len(ls) < n:
c = random.randint(0, total)
ls.append(c)
ls = sorted(ls)
ls.append(total)
for i in range(1, len(ls)):
rv.append(ls[i] - ls[i-1])
return rv
def f(z, w, a, b):
rv = []
indices = [x+w for x in positive_integers_with_sum(z, (b-a)-z*w)]
start = a
for i in indices:
i_start = random.randint(start, i+start-w)
i_end = random.randint(max(i_start+w, i+start-w), i+start)
rv.append([i_start, i_end - 1])
start+=i
return rv
def get_lists(n, z, w, a, b):
return [f(z, w, a, b) for _ in range(n)]
Выход:
>>> get_lists(5, 3, 5, 0, 15)
[[[0, 4], [5, 9], [10, 14]],
[[0, 4], [5, 9], [10, 14]],
[[0, 4], [5, 9], [10, 14]],
[[0, 4], [5, 9], [10, 14]],
[[0, 4], [5, 9], [10, 14]]]
>>> get_lists(4, 3, 5, 0, 100)
[[[45, 72], [74, 79], [92, 97]],
[[18, 23], [39, 44], [77, 97]],
[[12, 31], [37, 53], [83, 95]],
[[13, 46], [62, 87], [94, 100]]]
Средние интервальные размеры:
rv = [[],[],[]]
for i in range(100000):
t = f(3,5,0,100)
for i in range(3):
rv[i].append(abs(t[i][1] - t[i][0]))
Выход:
>>> np.mean(rv, axis=1)
array([16.10771, 16.35467, 16.21329])