Notas de algoritmo-programación dinámica-1

01 mochila

Introducción al problema

El problema estándar de la mochila 01 se refiere a una mochila con n (tipo int) artículos y peso máximo W (tipo int). La matriz de peso representa el peso del artículo, es decir, el peso [i] representa el peso del i-ésimo artículo, la matriz de valor representa el valor del artículo, es decir, el valor [i] representa el valor del i-ésimo artículo. Pregunte qué artículos empacar en la mochila para maximizar el valor total de los artículos, y cada artículo solo se puede cargar una vez.

Por ejemplo 1, suponga que el peso de la mochila es 4 y la información del artículo se describe en la tabla:

peso valor
Elemento 0 1 15
Objeto 1 3 20
Ítem ​​2 4 30

Transformación de problemas

Si el problema encontrado cumple con las características de la mochila 01, puede pensar si se puede transformar en un problema de mochila 01

  • Cada artículo (elemento) solo se puede usar una vez
  • La mochila está llena
  • El peso del elemento colocado (elemento) es el valor del elemento, y el valor también es el valor del elemento.

Solución

Retroceso

Cada elemento se recupera o no se recupera. Utilice el método de retroceso para buscar en todas las situaciones. La complejidad del tiempo es O (2 ^ n)

Programación dinámica

Utilice el método de programación dinámica para resolver el problema en cinco pasos. Los siguientes se describen todos con una matriz dp bidimensional para el ejemplo 1.

El primer paso es determinar el significado de la matriz dp

La matriz dp se muestra en la figura.
Inserte la descripción de la imagen aquí
Dp [i] [j] significa tomar cualquier elemento del subíndice [0 ~ i] y ponerlo en una mochila con una capacidad de j. La suma máxima del valor
i representa el elemento , yj representa la capacidad

  • Tenga en cuenta que i es menor que n. Por ejemplo, hay tres elementos en n = 3. Cuando i = 1, sólo puede seleccionar elementos numerados 0 y 1 y ponerlos en la mochila.
  • Tenga en cuenta que j es menor o igual que el peso de la mochila W. La mochila puede contener hasta W, pero la mochila correspondiente a la matriz dp actual puede contener hasta j

El segundo paso es determinar la fórmula de recurrencia

Solo dos direcciones pueden derivar dp [i] [j]

  • Introducido por dp [i-1] [j]. La capacidad actual de la mochila es j, y el valor máximo solo se puede seleccionar de los elementos numerados [0 ~ i-1]. Ahora se agregan los elementos con el número de elemento i, dp [i] [j] es dp [i-1] [ j]
  • Introducido por dp [i-1] [j-peso [i]. dp [i-1] [j-weight [i]] representa el valor máximo del artículo i cuando la capacidad de la mochila es j-weight [i]. Ahora la mochila simplemente deja libre el peso del artículo i, intente agregar el artículo i. Es decir, dp [i] [j] = dp [i-1] [j-peso [i]] + valor [i]

Entonces la fórmula de recurrencia es

dp [i] [j] = max (dp [i - 1] [j], dp [i - 1] [j - peso [i]] + valor [i])

El tercer paso de la inicialización

La inicialización de la matriz dp no puede violar la definición
de matriz dp. Se conoce por la fórmula recursiva de la matriz dp. La derivación de la matriz dp es utilizar el valor de la fila anterior de la matriz dp y el valor de la
columna anterior . Por lo tanto, la capacidad de la mochila es 0 cuando se inicializan la primera fila y la primera columna de la matriz dp , por lo que la inicialización completa es 0, es decir, dp [i] [0] = 0, i es 0 ~ n-1
Inserte la descripción de la imagen aquí

Solo se puede seleccionar el elemento 0 en la primera fila y la capacidad de la mochila aumenta gradualmente a W. Por lo tanto, en dp [0] [j], cuando la capacidad j es mayor o igual al peso del artículo 0, peso [0], dp [0] [j] es el valor del artículo 0, y cuando j es menos que eso, es 0.
Inserte la descripción de la imagen aquí
Entonces, al inicializar la primera línea, siga el recorrido de orden positivo de la fórmula recursiva, el código tiene dos bucles, si desea tener solo un bucle, debe usar el recorrido inverso

for (int j = W; j >= weight[0]; j--) {
    dp[0][j] = dp[0][j - weight[0]] + value[0];
}

Cuando se inicializa el recorrido de bucle, el código también debe seguir la fórmula de recurrencia, pero el recorrido de secuencia positiva agregará el elemento 0 varias veces

for (int j = weight[0]; j <= W; j++) {
    dp[0][j] = dp[0][j - weight[0]] + value[0];
}

El cuarto paso es determinar el orden transversal

La matriz dp inicializada en el tercer paso es la siguiente.
Inserte la descripción de la imagen aquí
Hay dos dimensiones transversales: los artículos y los pesos de la mochila, por lo que hay dos capas de bucles for. Está bien
atravesar los elementos primero o atravesar el peso de la mochila primero, pero es mejor atravesar los elementos primero.

for(int i = 1; i < n; i++) { // 遍历物品
    for(int j = 0; j <= W; j++) { // 遍历背包容量 
        if (j < weight[i]) dp[i][j] = dp[i - 1][j];
        else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
        
    }
}

El quinto paso es derivar la matriz dp

El resultado final de la matriz dp es el siguiente, el
Inserte la descripción de la imagen aquí
resultado final es dp [2] [4]

Si modifica la condición de juicio durante el recorrido:

if (j - weight[i] >= 0)  
  dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

La matriz dp se convierte en: el
Inserte la descripción de la imagen aquí
código completo es el siguiente:

 vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int W = 4; //背包重量
    int n = 3;  //物品数量

    // 二维数组
    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    // 初始化 
    for (int j = W; j >= weight[0]; j--) {
        dp[0][j] = dp[0][j - weight[0]] + value[0];
    }

    // weight数组的大小 就是物品个数
    for(int i = 1; i < n; i++) { // 遍历物品
        for(int j = 0; j <= W; j++) { // 遍历背包容量
            if (j - weight[i] >= 0)  dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
        }
        cout << dp[n][W]<<endl;
    }

Mejoramiento

Puede usar una matriz dp unidimensional (matriz rodante) para resolver el problema de la mochila 01.
Debido a que se encuentra que los datos de la fila anterior se pueden reutilizar, los datos de la fila anterior del primer tipo de matriz dp son directamente copiado en la siguiente fila,
por lo que la matriz dp se puede comprimir en una matriz unidimensional:
Dp: [0, 15, 15, 20, 35]
dp [j] representa una mochila con una capacidad de j, y el valor de el artículo transportado puede ser de hasta dp [j].
La fórmula de recurrencia es

dp [j] = max (dp [j], dp [j - peso [i]] + valor [i]);

Cabe señalar que el orden transversal de la matriz dp unidimensional es la capacidad de la mochila de grande a pequeña. Para garantizar que cada elemento solo se coloque una vez,
la secuencia transversal solo puede atravesar los elementos primero y luego atravesar la capacidad de la mochila

vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int W = 4; //背包重量
int n = 3;  //物品数量

// 初始化
vector<int> dp(W + 1, 0);
for(int i = 0; i < n; i++) { // 遍历物品
    for(int j = W; j >= weight[i]; j--) { // 遍历背包容量
       dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}
cout << dp[W] << endl;

Supongo que te gusta

Origin blog.csdn.net/MinutkiBegut/article/details/114131230
Recomendado
Clasificación