2012-03-07 16 views
5

Pracuję nad szybkimi i brudnymi skryptami do wykonywania niektórych zadań domowych z chemii, a jeden z nich przechodzi przez listy o stałej długości, w których sumują się wszystkie elementy dana stała. Dla każdego sprawdzam, czy spełniają niektóre dodatkowe kryteria i umieszczają je na innej liście.Tworzenie tablicy liczb, które sumują się pod podanym numerem

ja wymyśliliśmy sposób, aby spełnić kryteria Sum, ale wygląda przerażające i jestem pewien, że istnieje jakiś rodzaj pojętny chwili tutaj:

# iterate through all 11-element lists where the elements sum to 8. 
for a in range(8+1): 
for b in range(8-a+1): 
    for c in range(8-a-b+1): 
    for d in range(8-a-b-c+1): 
    for e in range(8-a-b-c-d+1): 
    for f in range(8-a-b-c-d-e+1): 
     for g in range(8-a-b-c-d-e-f+1): 
     for h in range(8-a-b-c-d-e-f-g+1): 
     for i in range(8-a-b-c-d-e-f-g-h+1): 
     for j in range(8-a-b-c-d-e-f-g-h-i+1): 
      k = 8-(a+b+c+d+e+f+g+h+i+j) 
      x = [a,b,c,d,e,f,g,h,i,j,k] 
      # see if x works for what I want 
+0

'[vals dla Vals w itertools.product (zakres (8), powtórz = 11), jeżeli suma (Vals) == 8]' jest piękniejsze, ale ** ** znacznie wolniej niż rozwiązania. – eumiro

+0

+1 - Rekwizyty do korzystania z komputera w celu zautomatyzowania odrabiania zadań domowych z chemii powtórkowej. –

+0

Mój wgląd jest następujący: w przypadku listy 11 liczb całkowitych wszystkich sumujących do 8, wiele liczb będzie zerowych. Szybkim sposobem na to byłoby znalezienie wszystkich sposobów sumowania liczb całkowitych do 8 - na przykład '8, 1 + 7, 2 + 6, 3 + 5, 4 + 4, 1 + 1 + 6, 1 + 2 + 5 ... ', a następnie po prostu permutuj tych z odpowiednią liczbą zer. –

Odpowiedz

1

Oto generator rekurencyjny, który dostarcza list w porządku leksykograficznym. Pozostawienie exact jako True daje żądany wynik, gdzie każda suma == limit; ustawienie exact na False podaje wszystkie listy z 0 < = sumą < = limit. Rekurencja korzysta z tej opcji, aby uzyskać wyniki pośrednie.

def lists_with_sum(length, limit, exact=True): 
    if length: 
     for l in lists_with_sum(length-1, limit, False): 
      gap = limit-sum(l) 
      for i in range(gap if exact else 0, gap+1): 
       yield l + [i] 
    else: 
     yield [] 
1

Generic, rekurencyjne rozwiązanie:

def get_lists_with_sum(length, my_sum): 
    if my_sum == 0: 
     return [[0 for _ in range(length)]] 

    if not length: 
     return [[]] 
    elif length == 1: 
     return [[my_sum]] 
    else: 
     lists = [] 
     for i in range(my_sum+1): 
      rest = my_sum - i 
      sublists = get_lists_with_sum(length-1, rest) 
      for sl in sublists: 
       sl.insert(0, i) 
       lists.append(sl) 

    return lists 

print get_lists_with_sum(11, 8) 
+0

Próbowałem po prostu to uruchomić. Och, to jest powolne ... Może przekształcić się w coś, co używa stosu zamiast pełnowymiarowej rekursji? –

+0

Oczywiście jest ukierunkowany na niskie wartości. Dla podanych liczb uważam, że jest to do przyjęcia. Budowanie pamięci podręcznej prawdopodobnie pomoże, ponieważ argumenty będą się powtarzać dość często. Nadal liczba możliwych kombinacji eksploduje dla argumentów o wyższej wartości. –

+0

Z argumentami '8,11', odradza mój procesor na kilka minut, zanim go zabiłem. Odpowiedź OP jest bardzo szybka (tylko * brzydka *.). –

Powiązane problemy