Convertir un problema de mochila acotado a un problema de mochila 0/1

12

Me encontré con un problema en el que el objetivo era usar programación dinámica (en lugar de otros enfoques). Hay una distancia a recorrer y un conjunto de cables de diferentes longitudes. ¿Cuál es el número mínimo de cables necesarios para recorrer la distancia exactamente?

Para mí, esto parecía un problema de mochila , pero dado que podría haber múltiplos de una longitud particular, era un problema de mochila limitado, en lugar de un problema de mochila 0/1. (Trate el valor de cada elemento como su peso). Tomando el enfoque ingenuo (y sin importar la expansión del espacio de búsqueda), el método que usé para convertir el problema de la mochila acotada en un problema de mochila 0/1, fue simplemente divida los múltiplos en singles y aplique el conocido algoritmo de programación dinámica. Desafortunadamente, esto lleva a resultados subóptimos.

Por ejemplo, cables dados:
1 x 10 pies,
1 x 7
pies, 1 x 6 pies,
5 x 3 pies,
6 x 2 pies,
7 x 1 pies

Si el alcance objetivo es 13 pies, el algoritmo DP elige 7 + 6 para abarcar la distancia. Un algoritmo codicioso habría elegido 10 + 3, pero es un empate para un número mínimo de cables. El problema surge cuando se trata de abarcar 15 pies. El algoritmo DP terminó eligiendo 6 + 3 + 3 + 3 para obtener 4 cables, mientras que el algoritmo codicioso elige correctamente 10 + 3 + 2 para solo 3 cables.

De todos modos, haciendo un escaneo ligero de conversión limitado a 0/1, parece ser el enfoque bien conocido para convertir múltiples elementos a {p, 2p, 4p ...}. Mi pregunta es cómo funciona esta conversión si p + 2p + 4p no se suma al número de elementos múltiples. Por ejemplo: tengo 5 cables de 3 pies. No puedo agregar {3, 2x3, 4x3} porque 3 + 2x3 + 4x3> 5x3. ¿Debo agregar {3, 4x3} en su lugar?

[Actualmente estoy tratando de asimilar el documento "Oregon Trail Knapsack Problem", pero actualmente parece que el enfoque utilizado no es una programación dinámica.]

Hormigas
fuente
1
Yo creo que esto es más conveniente math.stackexchange.com o incluso mathoverflow.net
Oded
3
Estaba dividido entre el stackoverflow genérico, y aquí. Al leer las preguntas frecuentes en ambos sitios, este sitio enumera primero las estructuras de datos y los algoritmos. Al leer las preguntas frecuentes para el sitio de matemáticas, parecía sugerir preguntar en el sitio de teoría.
Hormigas el

Respuestas:

1

Puede haber algún error en su código. Escribí el programa DP como lo menciona Naryshkin. Para el lapso objetivo 13, informa 6 + 7, y para 15, informa 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)

Si ajusta el orden de las longitudes de entrada, puede proporcionar otras soluciones óptimas. Por ejemplo, lens = 5*[3] + 6*[2] + 7*[1] + [10, 7, 6]dará 15 = 10 + 2 + 3.

jsz
fuente
¿De dónde sacaste la declaración if: 'if (w-weights [i] == 0 or t) y (K [i] [w] == 0 o t + valores [i] <K [i] [w] ): '? Si olvido ahora la fuente de mi algoritmo DP, pero no tuve ninguna verificación de cero, solo verifique '(valor t + [i] <K [i] [w])'
Hormigas
1
Está resolviendo el peso total exacto , lo que significa que cada vez que se selecciona un artículo, debemos asegurarnos de que se cumpla el peso exacto (del paso actual). Entonces, cuando decidimos elegir un elemento, la segunda cláusula "t + valores [i] <K [i] [w]" asegura que tendremos un valor total menor; pero antes de eso, también necesitamos completar el peso requerido, es decir, los primeros ítems i-1 deben poder completar el peso (peso-w [i]), de ahí la primera cláusula "si K [i-1] [w -weights [i]] "(estoy usando una variable temporal t para eso).
jsz
Hay dos cheques adicionales "w == pesos [i]" y "K [i] [w] == 0"; son necesarios y debido a cómo se inicializan las tablas; Creo que podrás distinguirlo para que no entre en detalles. (Cambié w-weights [i] == 0 a w == weights [i]; debería ser más claro).
jsz
1

La forma en que he visto que se usa para transformar un problema de mochila acotada en un 0/1 es tener varios elementos idénticos. Indique si tiene los siguientes elementos (dados como peso, utilidad):

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

Lo transformaría en un problema 0/1 usando elementos con

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

Y use un algoritmo 0/1 para resolverlo. Es probable que tenga múltiples soluciones de igual corrección, de modo que seleccione una arbitraria.


Ahora sobre su problema con el cable: me gustaría que la longitud del cable sea el ancho y que el valor de cada cable sea exactamente el mismo (llámelo 1, aunque cualquier valor positivo funcionará). Ahora, use su algoritmo de solución de mochila favorito, pero donde normalmente seleccionaría una solución (parcial) que maximice el valor, seleccione una que lo minimice. Además, ignore todas las soluciones que no tengan un peso total que iguale la capacidad. Probablemente pueda (intentar) escribir un algoritmo más concreto con código real si alguien lo quiere.

Konstantin Tarashchanskiy
fuente
Sí, eso es exactamente lo que estoy haciendo para completar el peso y el valor. Estaba calculando para el valor máximo, en lugar de mínimo. Acabo de cambiar el código para calcular el mínimo, como sugirió, e inicialicé la fila 0 de la tabla DP para que sea MAXINT. Aún el mismo resultado, la solución de programación dinámica para problemas de mochila todavía termina eligiendo 6 + 3 + 3 + 3 en lugar de 10 + 3 + 2 o 7 + 6 + 2.
Hormigas