其他分享
首页 > 其他分享> > 0-1背包问题

0-1背包问题

作者:互联网


title: 0-1背包问题
date: 2022-05-11 11:02:33
tags: 算法

0-1背包问题

蛮力枚举法

依次列出所有可能情况

n表示有n个商品, C表示容量

image-20220511145827916

其中颜色相同的是需要重复计算的

带备忘的递归

为了解决这个问题->需要大量计算重复的过程,这个时候我们可以引进一个“备忘录”,如果遇到需要重复计算的式子的话,我们可以直接重备忘录中获取。

image-20220511153243852

伪代码的实现:

KnapsackMR(i, c)

​ 输入:商品集合{1,...,i},背包容量c

​ 输出:最大总价格P[i, c]

​ if(c < 0) then 容量为零 返回负无穷

​ return 负无穷

​ end

​ if i ≤ 0 then 如果商品的个数小于零的话,返回零

​ return 0

​ end

​ if P[i, c] ≠ NULL then 如果备忘录中有这个的话就不用计算 直接返回即可

​ return P[i, c]

​ end

​ P1 = KnapsackMR(i-1, c-vi)

​ P2 = KnapasckMR(i-1, c)

​ p[i, c] <= max{P1 + pi, P2}

​ return P[i, c]

计算顺序:

image-20220511154801451

为了能够不递推,直接求解P[i,c],这就需要我们事先把备忘录表,全部填写上去

p[i,c]确定的方法需要让p[i-1, c]和p[i-1,c-vi]+pi 相比较,选取其中较大的哪一个

image-20220511154927285

代码实现

# 背包问题
# 第一个参数为商品数量
# 第二个参数为背包容量
# 第三个参数为价格表容量表
def memo_rec_matrix(num_commodity, size_knapsack, Price):
    # 创建备忘录格式
    memo = [ [ [] for i in range(size_knapsack+1)] for m in range(num_commodity+1)]

    # 创建追踪表格 0 表示不选择该商品,1表示选择该商品
    rec = [ [ [] for i in range(size_knapsack+1)] for m in range(num_commodity+1)]

    # 初始化备忘录 和 追踪表格
    for m in range(size_knapsack+1):
        memo[0][m] = 0
        rec[0][m] = 0
    

    for m in range(num_commodity+1):
        memo[m][0] = 0
        rec[m][0] = 0
    
    # 当我们商品数量为1 - num_commodity 的时候各种情况
    for i in range(1, num_commodity+1):
        # 当背包容量为1-size_knapsck的时候的各种情况
        for m in range(1, size_knapsack+1):
            # 如果背包容量小于第i个商品的体积的话,
            #   就让memo数组对应的 商品数量i行  和  背包容量m列的位置 等于上一行的这一列的容量,
            #       因为上一行这一列的容量是 这个容量是没有i个商品的容量最大值, 并且设置rec[i][m]这个位置为零
            if m < Price[0][i-1]:
                memo[i][m] = memo[i-1][m]
                rec[i][m] = 0
            # 如果背包容量大于第i个商品的体积的话,需要进行判断
            else:
                # 如果加上第i个商品之后的价值 小于没有加上该商品的价值的话,
                #   那么就把该位置设置成没有加上第i个商品的时候价值
                #      把rec该位置的坐标赋值为0 因为没有选择了该商品 
                if memo[i-1][m] > memo[i-1][m-Price[0][i-1]]+Price[1][i-1]:
                    memo[i][m] = memo[i-1][m]
                    rec[i][m] = 0
                # 如果大于的话直接赋值就行
                #   把rec该位置的坐标赋值为1 因为选择了该商品
                else:
                     memo[i][m] = memo[i-1][m-Price[0][i-1]]+Price[1][i-1]
                     rec[i][m] = 1
    return memo, rec
                

# 追踪数组
def track(rec, price):
    rec_num_line = len(rec)-1
    rec_num_column = len(rec[0])-1

    while(True):
        # 循环条件 商品数量为0
        if rec_num_line == 0:
            break
        elif rec[rec_num_line][rec_num_column] == 0:
            rec_num_line -= 1
        else:
            print(rec_num_line)
            rec_num_line -= 1
            rec_num_column -= price[0][rec_num_line]

price = [
    [10,3,4,5,4], # 体积
    [24,2,9,10,9]  # 价格
]


# 商品数量
num_commodity = 5
# 背包容量
size_knapsack = 13


memo, rec = memo_rec_matrix(num_commodity,size_knapsack,price)

标签:背包,容量,memo,问题,num,rec,size
来源: https://www.cnblogs.com/zjhnuil/p/16258304.html