Conversione di un problema dello zaino limitato in un problema dello zaino 0/1

12

Ho trovato un problema in cui l'obiettivo era utilizzare la programmazione dinamica (anziché altri approcci). C'è una distanza da misurare e una serie di cavi di diversa lunghezza. Qual è il numero minimo di cavi necessari per coprire esattamente la distanza?

Per me questo sembrava un problema nello zaino , ma dal momento che potevano esserci multipli di una lunghezza particolare, era un problema dello zaino limitato, piuttosto che un problema dello zaino 0/1. (Tratta il valore di ogni oggetto come il suo peso.) Prendendo l'approccio naif (e senza preoccuparsi dell'espansione dello spazio di ricerca), il metodo che ho usato per convertire il problema dello zaino limitato in un problema dello zaino 0/1, era semplicemente suddividere i multipli in singoli e applicare il noto algoritmo di programmazione dinamica. Sfortunatamente, ciò porta a risultati non ottimali.

Ad esempio, cavi dati:
1 x 10 piedi,
1 x 7 piedi,
1 x 6 piedi,
5 x 3 piedi,
6 x 2 piedi,
7 x 1ft

Se l'intervallo target è 13ft, l'algoritmo DP preleva 7 + 6 per coprire la distanza. Un algoritmo avido avrebbe scelto 10 + 3, ma è un pareggio per il numero minimo di cavi. Il problema sorge, quando si cerca di coprire 15 piedi. L'algoritmo DP ha finito per selezionare 6 + 3 + 3 + 3 per ottenere 4 cavi, mentre l'algoritmo greedy sceglie correttamente 10 + 3 + 2 per soli 3 cavi.

Ad ogni modo, facendo una leggera scansione della conversione delimitata a 0/1, sembra il noto approccio per convertire più elementi in {p, 2p, 4p ...}. La mia domanda è: come funziona questa conversione se p + 2p + 4p non si aggiunge al numero di elementi multipli. Ad esempio: ho 5 cavi da 3 piedi. Non riesco molto bene ad aggiungere {3, 2x3, 4x3} perché 3 + 2x3 + 4x3 > 5x3. Dovrei aggiungere {3, 4x3} invece?

[Attualmente sto cercando di ingannare il documento "Oregon Trail Knapack Problem", ma al momento sembra che l'approccio utilizzato non sia la programmazione dinamica.]

    
posta Ants 31.10.2011 - 21:20
fonte

2 risposte

1

Potrebbe essere un errore nel tuo codice. Ho scritto il programma DP come menzionato da Naryshkin. Per l'intervallo di destinazione 13, riporta 6 + 7, e per 15, riporta 2 + 6 + 7.

# weight: cable length
# total weight: target span
# value: 1 for each cable
# want minimum number of cables, i.e. minimum total value

def knapsack_01_exact_min(weights, values, W):
    # 0-1 knapsack, exact total weight W, minimizing total value
    n = len(weights)
    values = [0] + values
    weights = [0] + weights
    K = [[0 for i in range(W+1)] for j in range(n+1)]
    choice = [[0 for i in range(W+1)] for j in range(n+1)]
    for i in range(1, n+1):
        for w in range(1, W+1):
            K[i][w] = K[i-1][w]
            choice[i][w] = '|'
            if w >= weights[i]:
                t = K[i-1][w-weights[i]]
                if (w==weights[i] or t) and (K[i][w]==0 or t+values[i] < K[i][w]):
                    choice[i][w] = '\'
                    K[i][w] = t+values[i]
    return K[n][W], choice

def print_choice(choice, weights):
    i = len(choice)-1
    j = len(choice[0])-1
    weights = [0] + weights
    while i > 0 and j > 0:
        if choice[i][j]=='\':
            print weights[i],
            j -= weights[i]
        i -= 1
    print

lens = [10, 7, 6] + 5*[3] + 6*[2] + 7*[1]
values = (3+5+6+7)*[1]
span = 13
v, choice = knapsack_01_exact_min(lens, values, span)
print "need %d cables to span %d:" % (v,span),
print_choice(choice, lens)

span = 15
v, choice = knapsack_01_exact_min(lens, values, span)
print "need %d cables to span %d:" % (v,span),
print_choice(choice, lens)

Se si regola l'ordine delle lunghezze di input, può fornire altre soluzioni ottimali. Ad esempio, lens = 5*[3] + 6*[2] + 7*[1] + [10, 7, 6] darà 15 = 10 + 2 + 3.

    
risposta data 17.06.2012 - 04:41
fonte
1

Il modo in cui ho visto l'abitudine di trasformare un problema legato allo zaino in uno 0/1 è di avere più oggetti identici. Di 'se hai i seguenti oggetti (dati come peso, utilità):

  • 2 x 1, 2
  • 3 x 2, 3

Lo trasformeresti in un problema 0/1 utilizzando elementi con

  • 1, 2
  • 1, 2
  • 2, 3
  • 2, 3
  • 2, 3

E usa un algoritmo 0/1 per risolverlo. Probabilmente avrai più soluzioni di uguale correttezza, quindi ne selezioni una arbitraria.

Ora riguardo al problema del cavo: la lunghezza del cavo dovrebbe essere pari a quella del cavo e il valore di ciascun cavo è esattamente lo stesso (chiamalo 1, anche se qualsiasi valore positivo funzionerà). Ora, usa il tuo algoritmo di risoluzione di Knapsack preferito, ma dove normalmente sceglierai una soluzione (parziale) che massimizzi il valore, selezionane una che la minimizzi. Inoltre, ignorare tutte le soluzioni che non hanno un peso totale uguale alla capacità. Posso probabilmente (provare a) scrivere un algoritmo più concreto con codice effettivo se qualcuno lo vuole.

    
risposta data 07.12.2011 - 04:56
fonte

Leggi altre domande sui tag