Питон "Звезды и Бары" - PullRequest
       10

Питон "Звезды и Бары"

0 голосов
/ 30 ноября 2018

Я пытаюсь найти все возможные способы распространения n конфет среди k детей.Например, согласно формуле звездочек, количество способов распределить 96 конфет среди 5 детей составляет 100! / (96!*4!) = 3 921 225 кортежи всех возможных перестановок размера 5.

list2 = [item for item in it.product(range(97), repeat = 5)
             if sum(item) == 96]

Мой компьютер, кажется, перегруженсложность.Каждый кортеж потребляет 24 * 5 = 120 байт памяти.Это приводит к 921 225 * 120 = 470547000 байтов или 450 МБ.Не так уж и много.Почему ПК так медленно генерирует этот список?Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Вот один из способов заставить ваш подход работать.Использует itertools.combinations.Создание полного списка занимает несколько секунд.Для более быстрого подхода на основе numpy см. Нижнюю часть этого поста.

Он работает путем перечисления всех комбинаций четырех тактов от 1 до 100, всегда добавляя внешние такты от 0 до 101. Распределения для пяти детейтогда что между барами, то есть разность столбцов минус один.

import numpy as np
import itertools


bars = [0, 0, 0, 0, 0, 101]
result = [[bars[j+1] - bars[j] - 1 for j in range(5)] for bars[1:-1] in itertools.combinations(range(1, 101), 4)]

# sanity check
len(result)
# 3921225
# show few samples
from pprint import pprint
pprint(result[::400000])
# [[0, 0, 0, 0, 96],
#  [2, 26, 12, 8, 48],
#  [5, 17, 22, 7, 45],
#  [8, 23, 30, 16, 19],
#  [12, 2, 73, 9, 0],
#  [16, 2, 25, 40, 13],
#  [20, 29, 24, 0, 23],
#  [26, 13, 34, 14, 9],
#  [33, 50, 4, 5, 4],
#  [45, 21, 26, 1, 3]]

Почему у вас не так хорошо работает?Я думаю, в основном потому, что ваш цикл немного расточительный, 97 ^ 5 немного больше, чем 100, выберите 4.

Если вы хотите очень быстро, вы можете заменить itertools.combinations версией numpy:

https://stackoverflow.com/a/42202157/7207392

def fast_comb(n, k):
    a = np.ones((k, n-k+1), dtype=int)
    a[0] = np.arange(n-k+1)
    for j in range(1, k):
        reps = (n-k+j) - a[j-1]
        a = np.repeat(a, reps, axis=1)
        ind = np.add.accumulate(reps)
        a[j, ind[:-1]] = 1-reps[1:]
        a[j, 0] = j
        a[j] = np.add.accumulate(a[j])
    return a

fb = fast_comb(100, 4)
sb = np.empty((6, fb.shape[1]), int)
sb[0], sb[1:5], sb[5] = -1, fb, 100
result = np.diff(sb.T) - 1

result.shape
# (3921225, 5)
result[::400000]
# array([[ 0,  0,  0,  0, 96],
#        [ 2, 26, 12,  8, 48],
#        [ 5, 17, 22,  7, 45],
#        [ 8, 23, 30, 16, 19],
#        [12,  2, 73,  9,  0],
#        [16,  2, 25, 40, 13],
#        [20, 29, 24,  0, 23],
#        [26, 13, 34, 14,  9],
#        [33, 50,  4,  5,  4],
#        [45, 21, 26,  1,  3]])

Это занимает около одной секунды.

0 голосов
/ 30 ноября 2018

Я вижу две проблемы с вашей математикой.

Сначала вы описываете комбинацию .По сути, вы думаете (96 выбирают 5), что не охватывает все перестановки.

Во-вторых, перестановка будет на самом деле 96! / 91 !, что на на несколько порядков выше чем ~ 4 миллиона.

Просто добавив количество байтов, вы находитесь в широком диапазоне гигабайтов использования памяти сейчас, что может объяснить, почему вашмашина тормозит;одно только использование памяти, полученное от этого, могло сломать большинство современных потребительских машин.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...