2012-12-21 18 views
5

Ho una matrice e la sua lunghezza è X. Ogni elemento dell'array ha intervallo 1 .. L. Voglio scorrere in modo efficiente attraverso tutte le combinazioni di array che ha somma L.Come eseguire iterazioni con combinazioni di array con somma costante in modo efficiente?

soluzioni corrette per: L = 4 e X = 2

1 3 
3 1 
2 2 

soluzioni corrette per: L = 5 e X = 3

1 1 3 
1 3 1 
3 1 1 
1 2 2 
2 1 2 
2 2 1 

L'implementazione naive è (stupirsi) troppo lento per il mio problema (X ha fino a 8 nel mio caso e L è fino a 128).

Qualcuno potrebbe dirmi come si chiama questo problema o dove trovare un algoritmo veloce per il problema?

Grazie!

+2

Sembra a me come se siete alla ricerca di le * partizioni intere * di 'L' di lunghezza' X'. –

+2

Non è possibile farlo * efficientemente * (in letteratura, efficientemente = polinomiale). Esiste un numero esponenziale di soluzioni e per l'iterazione tutte richiedono tempi esponenziali. – amit

+0

Questo sarebbe un grande problema di euler del progetto =) –

risposta

8

Se ho capito bene, si è dato due numeri 1 ≤ XL e si desidera generare tutte le sequenze di numeri interi positivi di lunghezza X tale somma a L.

(Nota: questo è simile al integer partition problem, ma non lo stesso, perché si considera 1,2,2 di essere una sequenza diversa da 2,1,2, mentre nel problema di partizione intero ignoriamo l'ordine, in modo che questi sono considerati per essere la stessa partizione)

le sequenze che si sta cercando corrispondono alle combinations di X -. 1 articoli di L - 1. per, se mettiamo i numeri 1 a L - 1 nell'ordine, e scegliere X - 1 di loro, quindi le lunghezze di intervalli tra il scelto i numeri sono numeri interi positivi che sommano a L.

Per esempio, supponiamo che L è 16 e X è 5. Poi scegliere 4 numeri da 1 a 15 inclusi:

the four numbers 3, 7, 8, and 14 are chosen from 1 to 15

Aggiungi 0 all'inizio e 16 alla fine , e gli intervalli sono:

intervals 0–3, 3–7, 7–8, 8–14 and 14–16

e 3 + 4 + 1 + 6 + 2 = 16 come richiesto.

Così generate the combinations di X - 1 articoli di L-1, e per ciascuno di essi, convertirlo in una partizione trovando gli intervalli. Per esempio, in Python si potrebbe scrivere:

from itertools import combinations 

def partitions(n, t): 
    """ 
    Generate the sequences of `n` positive integers that sum to `t`. 
    """ 
    assert(1 <= n <= t) 
    def intervals(c): 
     last = 0 
     for i in c: 
      yield i - last 
      last = i 
     yield t - last 
    for c in combinations(range(1, t), n - 1): 
     yield tuple(intervals(c)) 

>>> list(partitions(2, 4)) 
[(1, 3), (2, 2), (3, 1)] 
>>> list(partitions(3, 5)) 
[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)] 

Ci sono (L-1)!/(X - 1)! (L - X)!combinazioni di X - 1 articoli su L - 1, per cui l'esecuzione di questo algoritmo (e le dimensioni della sua uscita) è esponenziale L. Tuttavia, se non si conta l'output, è necessario solo lo spazio O (L).

Con L = 128 e X = 8, ci sono 89,356,415,775 partizioni, quindi ci vorrà un po 'per l'uscita tutti!

(Forse se si spiega il motivo per cui si sta Computing queste partizioni, potremmo essere in grado di suggerire un modo di soddisfare le vostre esigenze senza dover a tutti loro produrre effettivamente.)

+0

Penso che questa implementazione potrebbe essere leggermente ottimizzata se si sposta 'intervalli 'fuori dal ciclo e si passa' c' come parametro di input - In questo modo non si sta creando un nuovo funzione per ogni combinazione. – mgilson

+0

@mgilson: ho spostato la definizione della funzione fuori dal ciclo per renderti felice. Ma questo tipo di ottimizzazione sembra un po 'futile di fronte al comportamento esponenziale del runtime del programma. Sarebbe meglio capire come evitare di calcolare queste partizioni. –

+0

Concordo - Si tratta di un'ottimizzazione super piccola di fronte al compito quasi senza speranza. Ma se stiamo per scrivere un'implementazione per questo, potrebbe anche essere una buona soluzione :-) – mgilson

Problemi correlati