Implement greedy algorithm, brute force method, and dynamic programming method to solve the fractional knapsack problem and 0-1 knapsack problem based on python (with full source code download)

Knapsack problem algorithm design

The problem requires selecting appropriate items from a collection of items to put into the backpack. On the premise that the total weight of the items put into the backpack does not exceed the capacity of the backpack, it is hoped that the total value of the items put into the backpack will be the largest. According to the requirements of whether some items are allowed to be put into the backpack, the backpack problem can be divided into [ fractional backpack problem ] and [ 0-1 backpack problem ].

1. Outline design

  • Fractional knapsack problem, using greedy algorithm to get the optimal solution.
  • For the 0-1 knapsack problem, if you want an approximate solution, use the greedy algorithm; if you want the optimal solution, use the brute force method, the dynamic programming method, and the dynamic programming method with improved memory function to solve it. For the two dynamic programming methods, return the final The resulting dynamic programming table.

The specific function design process of the algorithm is as follows:

2. Specific algorithm design

  • greedy algorithm

① To find the optimal solution to the fractional knapsack problem, the idea is to find the unit value of each item, and select the items to put into the knapsack in order from high to low. If the weight of the item is less than or equal to the knapsack capacity, put it into the knapsack; otherwise, put the item into the knapsack. Break it down and put some items into a backpack. When the remaining capacity of the backpack reaches 0, the loop stops and the optimal total value is returned. The function design is as follows:

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  #返回最优总价值

② To find an approximate solution to the 0-1 knapsack problem, first find the unit value of each item, use a loop statement, and select the item with the highest unit value each time to put it into the backpack. If the weight of the item is less than or equal to the backpack capacity, put it into the backpack, otherwise , compare the next item, until the remaining capacity of the backpack is 0 or all items have been traversed, stop the loop and return the optimal total value. The function design is as follows:

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
  • Brute force method

Find the optimal solution to the 0-1 knapsack problem. First, exhaustively enumerate all subsets of items, set a variable maxvalue that records the maximum value, traverse all subsets, and calculate the total weight of the items in each subset. If it can be loaded into the backpack, and the current backpack value is greater than maxvalue, the current value Assign a value to maxvalue, and finally loop through all item combinations to obtain the optimal solution. The function design is as follows:

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
  • dynamic programming

The dynamic programming algorithm finds the optimal solution to the 0-1 knapsack problem, initializes the dynamic programming table, and all elements in the table are 0. Cell F(i,j) represents i items and the total value of the items in the optimal solution of the backpack with load capacity j. According to the recursion relationship:

Use a loop to fill in the table row by row. The value F(n,c) of the last cell is the maximum total value required. The function is designed as follows:

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]   #最大总价值
  • Memory function improves dynamic programming algorithm

The focus of this algorithm is to maintain a table similar to that used by the bottom-up dynamic programming algorithm. Initialize the dynamic programming table. The first row and first column elements in the table are both 0, and other elements are -1, indicating that the cell has not been calculated yet. Pass. F(i,j) represents i items and the total value of the items in the optimal solution of the backpack with load capacity j. First check whether the value of the cell in the table is less than 0. If it is less than 0, use recursive call to calculate according to the recursive relationship of the dynamic programming method, and record the returned result in the table. Otherwise, directly return the value in the cell. The function design is as follows:

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]
  • Backtrack table cells to find the components of the optimal subset

Using while loops and conditional judgment statements, starting from the last cell, if F[i][j]>F[i-1][j], it indicates item i and F[i-1][jw[i]] An optimal subset of is included in the optimal solution; otherwise, item i is not part of the optimal subset, compare F[i-1][j] with F[i-2][j], when backtracking to the backpack When the remaining capacity is 0, the optimal solution is returned. The function design is as follows:

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. Project testing

Consider the example given by the following data:

  • fraction knapsack problem

The optimal total value obtained through the greedy algorithm is 38.333. The optimal solution is {item 2, item 3, item 4}. Only 2/3 of item 3 is put into the backpack.

  • 0-1 backpack problem

1. The greedy algorithm finds its approximate solution, and the maximum total value is 37, and the approximate solution is {item 1, item 2, item 4}.

2. Brute force method, dynamic programming method, and dynamic programming method with improved memory function are used to find the optimal solution. The optimal total value is 37, and the optimal solution is {item 1, item 2, item 4}. It can be seen that the value of each cell in the dynamic programming table F1 has been calculated. In F2, -1 indicates that there is no calculated value, that is, only 11 values ​​​​are calculated. Therefore, after applying the improved memory function, the dynamic programming method The efficiency has been improved.

According to the test results, it can be seen that for this example, the approximate solution obtained by the greedy algorithm is the same as the optimal solution obtained by the brute force method, that is, the approximate solution is the optimal solution, but this algorithm does not always give Find the optimal solution , the counterexample is as follows:

The approximate solution obtained by using the greedy algorithm is {item 1}, with a total value of 40; and the optimal solution obtained by using the brute force method is {item 2, item 3}, with an optimal total value of 50, that is, the approximate solution is not the optimal solution. .

Complete source code download

Implement greedy algorithm, brute force method, and dynamic programming method based on python to solve fractional knapsack problem and 0-1 knapsack problem source code + project description and comments.zip

Guess you like

Origin blog.csdn.net/DeepLearning_/article/details/132719797