2017-08-16 2 views
0

Geben Sie für einen Satz von Ganzzahlen 1,2 und 3 die Anzahl der Möglichkeiten an, die diese zu n addieren können. (Die Reihenfolge ist wichtig, dh n ist 5. 1 + 2 + 1 + 1 und 2 + 1 + 1 + 1 sind zwei verschiedene Lösungen)Wie finden Sie die Anzahl der Möglichkeiten, die die ganzen Zahlen 1,2,3 summieren können?

Meine Lösung beinhaltet die Aufteilung von n in eine Liste von 1en, wenn n = 5 , A = [1,1,1,1,1]. Und ich werde mehr Unterlisten rekursiv aus jeder Liste erzeugen, indem ich benachbarte Zahlen hinzufüge. A wird also 4 weitere Listen erzeugen: [2,1,1,1], [1,2,1,1], [1,1,2,1], [1,1,1,2] und jede diese Listen werden weiter Sublisten erzeugen, bis es einen abschließenden Fall wie [3,2] oder [2,3]

(in Python) Hier bin meine vorgeschlagene Lösung

ways = [] 
def check_terminating(A,n): 
    # check for terminating case 
    for i in range(len(A)-1): 
     if A[i] + A[i+1] <= 3: 
      return False # means still can compute 
    return True 

def count_ways(n,A=[]): 
    if A in ways: 
     # check if alr computed if yes then don't compute 
     return True 
    if A not in ways: # check for duplicates 
     ways.append(A) # global ways 
    if check_terminating(A,n): 
     return True # end of the tree 
    for i in range(len(A)-1): 
     # for each index i, 
     # combine with the next element and form a new list 
     total = A[i] + A[i+1] 
     print(total) 
     if total <= 3: 
      # form new list and compute 
      newA = A[:i] + [total] + A[i+2:] 
      count_ways(A,newA) 
      # recursive call 

# main    
n = 5 
A = [1 for _ in range(n)] 

count_ways(5,A) 
print("No. of ways for n = {} is {}".format(n,len(ways))) 

Darf ich wissen, ob ich erreicht bin auf dem richtigen Weg, und wenn ja, gibt es eine Möglichkeit, diesen Code effizienter zu machen?

Bitte beachten Sie, dass dies kein Münzwechsel Problem ist. Beim Münzwechsel ist die Reihenfolge des Auftretens nicht wichtig. In meinem Problem unterscheidet sich 1 + 2 + 1 + 1 von 1 + 1 + 1 + 2, aber beim Münzwechsel sind beide gleich. Bitte geben Sie für diese Antwort keine Lösungen zum Münzwechsel an.

Edit: Mein Code funktioniert, aber ich würde gerne wissen, ob es bessere Lösungen gibt. Vielen Dank für Ihre Hilfe :)

+0

Haben Sie dies durch einen Compiler ausgeführt? Erhalten Sie Fehler? Wenn nicht, dann versuchen Sie das zuerst, bevor Sie Fragen zu SO stellen. Wenn Sie möchten, dass Ihnen jemand sagt, wie _good_ Ihr Code ist, versuchen Sie Code Review. – jmoon

+2

Btw, das Problem, das Sie lösen, heißt "Partitionierung". – m69

+0

Muss dieser Zahlensatz 1, 2, 3 sein? – bendl

Antwort

5

die Rezidiv rel ation ist F (n + 3) = F (n + 2) + F (n + 1) + F (n) mit F (0) = 1, F (-1) = F (-2) = 0.Dies sind die tribonacci Zahlen (eine Variante der Fibonacci-Zahlen):

Es ist möglich, eine einfache O schreiben (n) Lösung:

def count_ways(n): 
    a, b, c = 1, 0, 0 
    for _ in xrange(n): 
     a, b, c = a+b+c, a, b 
    return a 

Es ist schwieriger, aber möglich, das Ergebnis in relativ wenige Arithmetik zu berechnen Operationen:

def count_ways(n): 
    A = 3**(n+3) 
    P = A**3-A**2-A-1 
    return pow(A, n+3, P) % A 

for i in xrange(20): 
    print i, count_ways(i) 
+0

Schöne Antwort Paul. Es sagt die richtige Anzahl von Möglichkeiten in 'O (n)' Zeit. Ich denke darüber nach, ob wir diese Lösungen auch drucken können, jetzt wo wir wissen, wie viele Lösungen tatsächlich möglich sind. – CodeHunter

+0

Können Sie erklären, woher diese erstaunliche zweite Formel kommt? Ich sehe es nicht erwähnt auf [OEIS A000073] (http://oeis.org/A000073) und ich bin interessiert zu erfahren, wie dieser Ansatz auf andere wiederkehrende Beziehungen verallgemeinert. –

+2

@PeterdeRivaz Wenn Sie den polynomischen Quotientenring betrachten: Z [X]/(X^3-X^2-X-1), berechnen Sie X^n in diesem Ring. Man beachte, dass man diese Berechnung in Z/(A^3-A^2-A-1) approximieren kann, solange "A" groß genug ist, dass die Koeffizienten nicht überlaufen. '3 ** (n + 3)' ist das A hier - und ist nur eine Zahl, die schneller wächst als die Tribonacci-Zahlen. Es gibt einen nützlichen Hintergrund (Fibonacci statt Tribonacci) hier: http://fare.tunes.org/files/fun/fibonacci.lisp –

3

Die Idee, die Sie beschreiben, klingt richtig. Es ist einfach, eine rekursive Funktion zu schreiben, die die richtige Antwort ... langsam erzeugt.

Sie können es dann schneller machen, indem Sie die Antwort memoisieren. Behalte einfach ein Wörterbuch mit Antworten, die du bereits berechnet hast. Prüfen Sie in Ihrer rekursiven Funktion, ob Sie eine vorberechnete Antwort haben. Wenn ja, gib es zurück. Wenn nicht, berechnen Sie es, speichern Sie diese Antwort im Wörterbuch und geben Sie die Antwort zurück.

Diese Version sollte schnell ausgeführt werden.

+0

Ein ausführliches Beispiel für die Auswirkung von Memo-Elementen auf einen Partitionierungsalgorithmus finden Sie z. Diese Antwort: https://stackoverflow.com/questions/32907406/is-there-an-efficient-algorithm-for-integer-partitioning-with-restricted-number/32918426#32918426 – m69

+0

Memoization mit der Art, wie Sie gesagt haben, wird nicht verfolgen Sie die Reihenfolge des Auftretens. Diese Methode wäre ideal, wenn die Reihenfolge hier nicht wichtig wäre. Ich kann keine Memotisierung mit diesem Weg hier helfen. – CodeHunter

+0

@CodeHunter Solange die rekursive Funktion korrekt ist, ist die Memo-Funktion auch. Die Reihenfolge der Erscheinung in der rekursiven Funktion zu verfolgen ist einfach - es ist tatsächlich schwieriger, die Reihenfolge der Erscheinung nicht zu verfolgen. – btilly

2

Ein O (n) Verfahren möglich:

def countways(n): 
    A=[1,1,2] 
    while len(A)<=n: 
     A.append(A[-1]+A[-2]+A[-3]) 
    return A[n] 

Die Idee ist, dass wir arbeiten können, wie viele Möglichkeiten, eine Sequenz mit n zu machen, indem jede Wahl unter Berücksichtigung (1,2,3) für die letzte Partitionsgröße

z.B. zu zählen Entscheidungen für (1,1,1,1) berücksichtigen:

  1. Entscheidungen für (1,1,1) durch eine 1
  2. Entscheidungen für (1,1) durch ein 2
  3. gefolgt gefolgt
  4. Entscheidungen für (1), gefolgt von einem 3

Wenn Sie die Ergebnisse (statt nur die Zählung) benötigen, können Sie diesen Ansatz anpassen, wie folgt:

cache = {} 
def countwaysb(n): 
    if n < 0: 
     return [] 
    if n == 0: 
     return [[]] 
    if n in cache: 
     return cache[n] 
    A = [] 
    for last in range(1,4): 
     for B in countwaysb(n-last): 
      A.append(B+[last]) 
    cache[n] = A 
    return A 
Verwandte Themen