No puedo visualizar la tabla 2D que creamos para el problema 0/1 Knapsack. ¿Alguien puede ayudar?

Veamos primero la solución recursiva al problema.

Aquí, consideramos que wt[i] denota el costo de i-party, y val[i] denota el valor divertido para i-party. W denota el costo máximo proporcionado. N es el número total de partes.

Definamos una función int knapSack( int W, int wt[], int val[], int n) , que devolverá la máxima “diversión” que puede obtenerse de un máximo de ” W ” costo n número de partes .

¿Cuál debería ser el caso base para la función recursiva anterior? Obviamente, si el costo máximo que se nos da es cero ( W==0 ), entonces no podremos participar en ninguna fiesta, lo que obviamente no es divertido, por lo tanto, la diversión máxima en este caso es 0. Además, si el número de fiestas es cero, no tendremos la oportunidad de divertirnos ( n==0 ). Por lo tanto, el caso base de la función es

if (n == 0 || W == 0)

return 0;

Ahora para la siguiente parte. Tenemos suficiente dinero y suficientes fiestas. Ahora, ¿qué pasa si el costo de la enésima parte ( wt[n-1 ) en sí es mayor que el costo de todo el presupuesto ( W ) que se nos proporciona? No tiene sentido llorar desesperadamente por algo que no puedes conseguir. Sabes que es hora de olvidar y seguir adelante con lo que Dios te ha dado en lugar de culparlo por las cosas que no te dio. Entonces, la cantidad de “diversión” que obtienes es independiente de si consideras la enésima fiesta o no. Entonces, reducimos el número de cálculos al eliminar los imposibles.

if (wt[n-1] > W)

return knapSack(W, wt, val, n-1);

Ahora que tiene suficiente dinero para ir a la enésima fiesta, todavía no está satisfecho. Desea divertirse tanto como quiera con el dinero limitado que tiene. Entonces, siéntate cerca de la puerta de entrada con un bolígrafo y papel y comienza a calcular si vale la pena ingresar a esta enésima fiesta o no. Tienes 2 opciones:

i) Ingrese a esta enésima fiesta, gaste el dinero ( wt[n-1] ), diviértase que esta enésima fiesta le puede dar, y luego salga de la fiesta con su bolsillo menos pesado (dinero restante = W-wt[n-1] ). Sin embargo, te divertiste un poco ( val[n-1] ), y tienes n-1 fiestas más para satisfacer tu interminable enfriamiento de diversión. Entonces, considerando que tomaste esta decisión, ¿qué devolverá la función actual? Respuesta: val[n-1] + knapSack(W-wt[n-1], wt, val, n-1)

ii) O puede ignorar esta fiesta y buscar las otras n-1 , pero esta vez, su bolsillo está lleno del dinero original W , pero aún no se ha divertido. Entonces esto debería devolver knapSack(W, wt, val, n-1)

Entonces, considerando las dos opciones anteriores, ¿cuál debería tomar? ¡Obviamente el que te brinda más diversión! Entonces, la declaración final se verá así:

else return max( val[n-1] + knapSack(W-wt[n-1], wt, val, n-1),

knapSack(W, wt, val, n-1)

);

El enfoque Greedy completo se parece a esto

int knapSack (int W, int wt [], int val [], int n)
{
si (n == 0 || W == 0)
devuelve 0;

si (wt [n-1]> W)
return knapSack (W, wt, val, n-1);

de lo contrario, devuelve max (val [n-1] + knapSack (W-wt [n-1], wt, val, n-1),
knapSack (W, wt, val, n-1)
);
}


Pero no desea perder tanto tiempo para calcular las mismas cosas una y otra vez donde debería divertirse tanto. Entonces, necesitas la ayuda de DP. Del enfoque codicioso queda claro que para calcular la diversión para la enésima fiesta, primero debemos calcular la diversión para la fiesta n-1. Entonces, para reducir los cálculos, almacenamos los valores de los valores más bajos en una matriz 2D, de modo que no tengamos que calcular los valores anteriores una y otra vez. Entonces tomamos una matriz 2D K [n + 1] [W + 1]. Ahora, ¿qué denota K [i] [j]? K [i] [j] denota la cantidad de diversión que tendremos, teniendo en cuenta que hay i (el número de fila) número de fiestas, y j (el número de columna) es el Peso total que se nos otorga (desglosando así el problema). Considere el ejemplo, val[]={1,4,5,7} y wt[]={1,3,4,5} . K[0][0] será igual a cero (caso base). En cambio, si cualquiera de i o j es 0, K[i][j] es igual a 0. ¿Qué denotará K [1] [1]? La cantidad máxima de diversión que puede obtener cuando solo hay 1 parte de valor de diversión val[1-1] y el costo de entrada es wt[1-1] , y su presupuesto total es 1. ¿Qué es K [1] [2] ? La cantidad máxima de diversión que puede obtener cuando solo hay 1 parte de valor de diversión val[1-1] y el costo de entrada es wt[1-1] , y su presupuesto total es 2. De esta manera, completa la matriz según la fórmula dorada – K[i][w]=max(val[i-1]+K[i-1][j-wt[i-1]],K[i-1][j]);

¿Cuál es la respuesta final? La máxima diversión que tuvo considerando n cantidad de fiestas y W como el dinero total que le dieron. ¿Dónde debería estar la respuesta en la matriz? K[n][W] .


Luego viene cómo calcular el peso óptimo. Cree otra matriz int wg[n+1][W+1] que almacenará el peso óptimo para su fila y columna correspondiente en la matriz K[][] . wg[i][j] calcula el peso total para i no de las partes y j cantidad de costo. Para obtener un valor óptimo, encuentre el valor mínimo de los elementos en la última fila (enésima fila), y ese valor mínimo es la solución óptima.

EDITAR: No se requiere una nueva matriz. Lo mismo se puede hacer con la matriz K[][]

Puede consultar mi solución aquí: RudraNilBasu / C-CPP-Codes o una discusión más detallada sobre 0/1 Mochila – Programación dinámica | Conjunto 10 (problema de mochila 0-1) – GeeksforGeeks.

No piense en el código al principio, esa es la razón por la que “no puede ver cómo se llenan los elementos en la tabla 2D” y “cómo calcular el peso total que da la solución óptima”.

Hay muchas maneras de llegar a la solución de programación dinámica (DP). El que encuentro más fácil es seguir un enfoque paso a paso.

  1. Primero encuentre una solución recursiva.
  2. Convierta esto en un algoritmo de arriba hacia abajo.
  3. Convierta esto en un algoritmo de abajo hacia arriba.

Por ejemplo, en un problema de mochila 0/1, digamos que tiene 5 artículos con sus pesos y precios escritos.

Ahora sabe que un elemento ‘x’ (digamos 4 bloques de $ 12Kg) está seleccionado o no para el conjunto de solución final (conjunto de elementos cuyo peso es menor o igual a 15 pero el costo se maximiza). Entonces, su problema se reduce a 2 subproblemas, ahora tenemos que encontrar qué opción nos daría un valor más alto.

¿Elegir un artículo de 12 kg para nuestra mochila (problema A en la figura) o desechar el artículo de 12 kg (problema B)?

Esto nos da 2 subproblemas, ahora tiene que encontrar cuál de las dos opciones le dará un valor más alto para la mochila, la solución a los subproblemas no debería depender en modo alguno del último paso (es decir, el valor devuelto por el problema A debería no se verá afectado por los pasos que tomamos en el primer nodo), por lo tanto, tendremos que volver a describir nuestros dos nuevos problemas.

Eso es fácil de hacer porque en el problema A ha seleccionado la masa de 12 kg, por lo que la nueva mochila tiene capacidad 3 (15-12), por lo que debemos encontrar la mejor solución para la mochila de tamaño 3 Kg (pero ahora no elija el artículo de 12 kg porque ya está cuidado, simplemente elimine el artículo x a partir de ahora).

Para el problema B, no ha elegido el artículo de 12 kg, por lo tanto, su mochila todavía tiene una capacidad de 15 kg.

¿Cómo usará la solución del problema A y B para encontrar la solución del problema inicial?

La solución de los problemas A y B es el valor máximo de la mochila posible usando esas configuraciones (tamaño de la mochila 3 o 15 en este caso …) por lo que son un problema de la mochila en sí mismos sin el artículo de 12 kg.

ahora tiene que encontrar cuál de estos valores es mayor teniendo en cuenta que después de seleccionar 12 kg de masa ganó +4 antes de generar el problema A y +0 (nada, porque descartó el artículo de 12 kg)

Solución final = maximumOf (Solución (A) + 4, Solución (B) +0)

Si hay una lista de ítems, la solución después de escoger / descartar el i-ésimo ítem viene dada por la solución [i].

El peso y el valor del i-ésimo elemento están representados por el peso [i] y el valor [i] respectivamente

Esta ecuación de solución final puede reescribirse como

FinalSolution [i] = max (solución (15 – peso [i]) + valor [i], solución (15))

Este es el quid de la solución DP.

Ahora, ¿qué debemos hacer si 15 – peso [i] es un número negativo? ?

¿Cómo funciona la solución para realizar un seguimiento de los elementos que ha considerado?


Si observa que la ‘i’ en FinalSolution [i] es Básicamente la cantidad de artículos que actualmente hemos empacado (considerado agregar) en la mochila.

Aquí hay una versión más ampliada del árbol, cada burbuja representa un subproblema con el tamaño de la mochila escrito en él.

entonces, en cada paso, necesita saber el número de artículo en el que se encuentra (porque tendrá que hacer un seguimiento de los artículos que ha considerado o no) y la capacidad de la mochila. Estos son los dos números que ve en la tabla.

por lo tanto, para realizar un seguimiento de los elementos ya considerados antes, necesitamos agregar otro parámetro a la función de solución.

solución (i, j) donde i son los elementos ya considerados y j es la capacidad de la mochila.

ahora la ecuación final se puede escribir como

FinalSolution [i] [j] = max (solución (i – 1, j – peso [i]) + valor [i], solución (i – 1, j))

por lo tanto, i y j (elementos considerados y tamaño de la mochila) son las dos únicas dimensiones necesarias para describir un subproblema.


Ahora puede reducir cada problema a subproblemas y resolverlo de forma recursiva, pero al hacerlo volverá a calcular las soluciones para muchos subproblemas en numerosas ocasiones, puede usar la memorización para mejorar esto, básicamente crear una matriz 2D ( llamemos a esto dp de matriz 2d ) que almacena las respuestas para el subproblema y si necesitamos esta solución nuevamente, simplemente podemos consultar esta matriz 2D.

Esta solución debería funcionar bien, pero podría mejorarse aún más eliminando la recursividad cambiando esta solución a un algoritmo ascendente. En esto, comenzará a calcular las respuestas para cada elemento de la matriz dp de abajo hacia arriba, es decir, primero encontrará las respuestas para cada tamaño de mochila cuando solo puede seleccionar un solo elemento (por ejemplo, el elemento 5), por ejemplo, ya sabe que si no puede elija cualquier artículo o si el tamaño de la mochila es 0, el mejor valor que puede obtener es 0. Entonces, primero llenamos cada elemento de dp con 0 y luego comenzamos nuestro cálculo.

Así que ahora calcularemos el mejor valor para cada tamaño de mochila posible dado que solo podemos seleccionar el quinto elemento, luego incluir el cuarto elemento, luego el tercero y así sucesivamente. hacemos esto aplicando nuestra ecuación finalSolution pero cuidando los valores negativos de j – peso [i].

dp [número de artículos] [tamaño máximo de mochila] = {{0}}; // inicializar a 0

for (int i = 1; i <= número de elementos en la lista; i ++) {
for (int j = 1; j <= peso máximo posible de la mochila; j ++) {
if (j> = weight [i]) // comprueba si j – weight [i] no es negativo {
int notSelectedVal = dp [i-1] [j];
int selectedVal = dp [i-1] [j-weight [i]] + valor [i];
dp [i] [j] = max (notSelectedVal, selectedVal);
}
más{
dp [i] [j] = dp [i-1] [j]; // equivalente a notSelectedVal
}
}
}

// la respuesta finalmente se calcula en
// dp [número de artículos] [tamaño máximo de mochila]

No se confunda con la numeración, se puede hacer desde cualquier lado en la descripción. He usado la numeración (es decir, ‘i’) desde abajo, pero en el código la he usado desde arriba.

Puede modificar fácilmente este algoritmo para resolver el problema en cuestión. Intenté ayudarte a visualizar lo que está sucediendo.

Oh dios es 02:49 😛

La idea subyacente detrás del problema de la mochila es el movimiento restringido que está estrechamente relacionado con ambos: la superposición de una realidad 3D en un lienzo 2D y con la idea más general de optimización. Entonces, en mi humilde opinión, su problema puede resolverse si enfoca sus pensamientos y acciones en estos dos niveles. Hacer un curso sobre Ingeniería Gráfica catalizará el proceso de cambio transdimensional a nivel mental.

¡Y uno puede mejorar sus habilidades de optimización mientras hace prácticamente cualquier cosa! Intente usar los codos para apagar las luces. Intente pararse (y caminar) con sus curas elevadas (con solo aire entre usted y el suelo allí). Uno puede experimentar con varios tipos de estilos de vida, con la minimización del consumo y las indulgencias como objetivo. De hecho, eso dará algunas de las mejores lecciones sobre optimización.

Las acciones específicas que conducen a abstracciones similares están bastante interconectadas. Y así el temperamento puede viajar a través de tales acciones de manera más eficiente.

Este enlace puede ser útil, explica en detalle tanto el enfoque recursivo de fuerza bruta como el enfoque de programación dinámica que resuelve el problema que ocurre en el enfoque recursivo junto con el programa.

Explica con imágenes de datos de Matrix en cada paso para una mejor comprensión.
El problema de la mochila