Implemente un algoritmo codicioso, un método de fuerza bruta y un método de programación dinámica para resolver el problema de la mochila fraccionaria y el problema de la mochila 0-1 basado en Python (con descarga del código fuente completo)

Diseño de algoritmo de problema de mochila.

El problema requiere seleccionar los artículos apropiados de una colección de artículos para poner en la mochila. Partiendo de la premisa de que el peso total de los artículos puestos en la mochila no excede la capacidad de la mochila, se espera que el valor total de los artículos Poner en la mochila será el más grande. De acuerdo con los requisitos de si se permite poner algunos artículos en la mochila, el problema de la mochila se puede dividir en [ problema de mochila fraccionada ] y [ problema de mochila 0-1 ].

1. Diseño del esquema

  • Problema de mochila fraccional, utilizando un algoritmo codicioso para obtener la solución óptima.
  • Para el problema de la mochila 0-1, si desea una solución aproximada, use el algoritmo codicioso; si desea la solución óptima, use el método de fuerza bruta, el método de programación dinámica y el método de programación dinámica con función de memoria mejorada para resolverlo. Para los dos métodos de programación dinámica, devuelve la tabla de programación dinámica resultante.

El proceso de diseño de funciones específicas del algoritmo es el siguiente:

2. Diseño de algoritmo específico

  • algoritmo codicioso

① Para encontrar la solución óptima al problema de la mochila fraccionaria, la idea es encontrar el valor unitario de cada artículo y seleccionar los artículos que se colocarán en la mochila en orden de mayor a menor. Si el peso del artículo es menor que o igual a la capacidad de la mochila, póngalo en la mochila, de lo contrario, coloque el artículo en la mochila, rómpalo y coloque algunos artículos en la mochila. Cuando la capacidad restante de la mochila llega a 0, el ciclo se detiene y se devuelve el valor total óptimo. El diseño de funciones es el siguiente:

def Greedy_F(n,c):   #贪心算法求解分数背包问题最优解
    #n表示物品个数,c表示背包容量
    global opt1
    Sumvalue1 = 0  #记录背包内物品总价值
    opt1 = [0]*n  #记录选择的物品
    danwei_v = []
    for i in range(n):
        d = v[i]/w[i]    #计算物品单位价值
        danwei_v.append(d)   
    value = list(enumerate(danwei_v))  #enumerate()函数将物品序号与其对应单位价值组合为一组数对
    value.sort(key=lambda a: a[1], reverse=True)  #按物品单位价值降序排序
    while c > 0:
        for i in range(n):
            if  w[value[i][0]] <= c:
                Sumvalue1 += v[value[i][0]]
                opt1[value[i][0]] = w[value[i][0]]
                c -= w[value[i][0]]
            else:
                Sumvalue1 += c*danwei_v[value[i][0]]
                opt1[value[i][0]] = c
        else:
            break
    return Sumvalue1  #返回最优总价值

② Para encontrar una solución aproximada al problema de la mochila 0-1, primero encuentre el valor unitario de cada artículo, use una instrucción de bucle y seleccione el artículo con el valor unitario más alto cada vez para colocarlo en la mochila. el artículo es menor o igual a la capacidad de la mochila, colóquelo en la mochila; de lo contrario, compare el siguiente artículo, hasta que la capacidad restante de la mochila sea 0 o todos los artículos hayan sido recorridos, detenga el ciclo y devuelva el valor total óptimo . El diseño de funciones es el siguiente:

def Greedy_I(n,c):     #贪心算法求解0-1背包近似解
    global opt2
    Sumvalue2 = 0
    opt2 = [0]*n
    danwei_v = []
    for i in range(n):
        d = v[i]/w[i]
        danwei_v.append(d)
    value = list(enumerate(danwei_v))
    value.sort(key=lambda a: a[11], reverse=True)
    while c > 0:
        for i in range(n):
            if  w[value[i][0]] <= c:
                Sumvalue2 += v[value[i][0]]
                opt2[value[i][0]] = 1
                c -= w[value[i][0]]
        else:
            break
    return Sumvalue2
  • método de fuerza bruta

Encuentre la solución óptima al problema de la mochila 0-1. Primero, enumere exhaustivamente todos los subconjuntos de artículos, establezca un valor máximo variable que registre el valor máximo, recorra todos los subconjuntos y calcule el peso total de los artículos en cada subconjunto, si se puede cargar en la mochila y el valor actual de la mochila es mayor que maxvalue, el valor actual Asigne un valor a maxvalue y finalmente recorra todas las combinaciones de elementos para obtener la solución óptima. El diseño de la función es el siguiente:

def Brute(n,c):   #蛮力法求解0-1背包最优解
    a = [0,1]
    l = list(product(a,repeat=n))
    #求解[0,1]中元素的全排列组合,repeat=n表示单个元素最大重复次数
    maxvalue = 0    #记录最大价值
    global opt3
    opt3 = []
    for i in range(len(l)):   #遍历所有子集
        sumweight = 0  # 将总重量与总价值清零,计算下一子集
        sumvalue = 0
        for j in range(n):
            sumweight += l[j][i]*w[j]   #计算子集的总重量
            sumvalue += l[j][i]*v[j]
        if sumweight <= c and sumvalue > maxvalue:   #判断该子集物品能否装入背包,并与最大价值比较进行更新
            maxvalue = sumvalue
            opt3 = list(l[i])
    return maxvalue
  • programación dinámica

El algoritmo de programación dinámica encuentra la solución óptima al problema de la mochila 0-1, inicializa la tabla de programación dinámica y todos los elementos de la tabla son 0. La celda F(i,j) representa i artículos y el valor total de los artículos en la solución óptima de la mochila con capacidad de carga j. Según la relación de recursividad:

Utilice un bucle para completar la tabla fila por fila. El valor F(n,c) de la última celda es el valor total máximo requerido. La función está diseñada de la siguiente manera:

def DP(n,c):   #动态规划法求解0-1背包问题最优解
    for i in range(1,n+1):
        for j in range(1,c+1):
            if j-w[i-1] < 0:
                F1[i][j] = F1[i-2][j]   #F1为初始化动态规划表,且为全局变量
            else:
                F1[i][j] = max(F1[i-1][j],F1[i-1][j-w[i-1]]+v[i-1])
    return F1[n][c]   #最大总价值
  • La función de memoria mejora el algoritmo de programación dinámica

El objetivo de este algoritmo es mantener una tabla similar a la utilizada por el algoritmo de programación dinámica ascendente. Inicialice la tabla de programación dinámica. Los elementos de la primera fila y la primera columna de la tabla son 0 y los demás elementos son -1. indicando que la celda aún no ha sido calculada. F(i,j) representa i artículos y el valor total de los artículos en la solución óptima de la mochila con capacidad de carga j. Primero verifique si el valor de la celda en la tabla es menor que 0. Si es menor que 0, use la llamada recursiva para calcular de acuerdo con la relación recursiva del método de programación dinámica y registre el resultado devuelto en la tabla. De lo contrario, Devuelve directamente el valor en la celda. El diseño de funciones es el siguiente:

def MFK(i,j):   #记忆功能改进动态规划法
    value = 0
    if F2[i][j] < 0:    #F2为初始化动态规划表,且为全局变量
        if j < w[i-1]:
            value = MFK(i-1,j)
        else:
            value = max(MFK(i-1,j),v[i-1]+MFK(i-1,w[i-1]))
        F2[i][j] = value  #注意缩进
    return F2[i][j]
  • Retroceder las celdas de la tabla para encontrar los componentes del subconjunto óptimo

Usando bucles while y declaraciones de juicio condicional, comenzando desde la última celda, si F[i][j]>F[i-1][j], indica el elemento i y F[i-1][jw[i]] Un subconjunto óptimo de está incluido en la solución óptima; de lo contrario, el elemento i no es parte del subconjunto óptimo, compare F[i-1][j] con F[i-2][j], al retroceder hasta la mochila Cuando la capacidad restante es 0, se devuelve la solución óptima. El diseño de funciones es el siguiente:

def show(F,n,c):   #F为动态规划表
    global opt4
    opt4 = [0]*n   #记录物品选择状态
    i = n
    j = c
    while c > 0:
        if F[i][j] > F[i-1][j]:
            opt4[i-1] = 1
            j -= w[i - 1]
            c -= w[i - 1]
            i -= 1
        else:
            i -= 1
    return opt4

3. Pruebas del proyecto

Considere el ejemplo dado por los siguientes datos:

  • problema de fracción de mochila

El valor total óptimo obtenido mediante el algoritmo codicioso es 38,333. La solución óptima es {elemento 2, elemento 3, elemento 4}. Solo se ponen 2/3 del elemento 3 en la mochila.

  • 0-1 problema de mochila

1. El algoritmo codicioso encuentra su solución aproximada, el valor total máximo es 37 y la solución aproximada es {elemento 1, elemento 2, elemento 4}.

2. Para encontrar la solución óptima se utilizan el método de fuerza bruta, el método de programación dinámica y el método de programación dinámica con función de memoria mejorada. El valor total óptimo es 37 y la solución óptima es {elemento 1, elemento 2, elemento 4}. Se puede observar que se ha calculado el valor de cada celda en la tabla de programación dinámica F1, en F2 -1 indica que no hay ningún valor calculado, es decir, solo se calculan 11 valores, por lo tanto, luego de aplicar la función de memoria mejorada, el método de programación dinámica Se ha mejorado la eficiencia.

Según los resultados de la prueba, se puede ver que para este ejemplo, la solución aproximada obtenida por el algoritmo codicioso es la misma que la solución óptima obtenida por el método de fuerza bruta, es decir, la solución aproximada es la solución óptima, pero esta El algoritmo no siempre da Encuentra la solución óptima , el contraejemplo es el siguiente:

La solución aproximada obtenida usando el algoritmo codicioso es {ítem 1}, con un valor total de 40; y la solución óptima obtenida usando el método de fuerza bruta es {ítem 2, ítem 3}, con un valor total óptimo de 50, es decir, la solución aproximada no es la solución óptima.

Descarga completa del código fuente

Implemente un algoritmo codicioso, un método de fuerza bruta y un método de programación dinámica basados ​​en Python para resolver el problema de la mochila fraccionaria y el código fuente del problema de la mochila 0-1 + descripción del proyecto y comentarios.zip

Supongo que te gusta

Origin blog.csdn.net/DeepLearning_/article/details/132719797
Recomendado
Clasificación