Python 背包问题

✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。
个人主页:小嗷犬的个人主页
个人网站:小嗷犬的技术小站
个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。


本文目录

    • 背包问题
    • 0-1 背包问题
    • 完全背包问题
    • 多重背包问题


背包问题

背包问题Knapsack Problem)是一类常见的组合优化问题。其问题描述为:给定一个固定大小、能够携重 W W W 的背包,以及一组有价值和重量的物品,找出一个最佳解决方案,使得装入背包的物品总重量不超过 W W W,且总价值最大。

Python 背包问题_第1张图片

通常情况下,背包问题可以分为以下三类:

  • 0-1 背包问题:每种物品仅有一件,可以选择放或不放。
  • 完全背包问题:每种物品有无限件,可以选择放多少件或不放。
  • 多重背包问题:每种物品有 n i n_i ni 件,可以选择放多少件或不放。

本文将介绍如何使用 Python 解决以上三类背包问题。


0-1 背包问题

0-1 背包问题0-1 Knapsack Problem)是最基础的背包问题。其问题描述为:给定一个固定大小、能够携重 W W W 的背包,以及 N N N 个价值、重量分别为 v i v_i vi w i w_i wi 的物品,找出一个最佳解决方案,使得装入背包的物品总重量不超过 W W W,且总价值最大。

有一个容量为 10 10 10 的背包,现有 4 4 4 个物品,其价值和重量分别为:

物品 1 2 3 4
价值 1 3 5 9
重量 2 3 4 7

求背包能装下的最大价值以及取得最大价值时的物品组合。

N = 4  # 物品数量
W = 10  # 背包容量
v = [0, 1, 3, 5, 9]  # 物品价值
w = [0, 2, 3, 4, 7]  # 物品重量
dp = [[0] * (W + 1) for _ in range(N + 1)]  # dp[i][j] 表示前 i 个物品放入容量为 j 的背包的最大价值
flag = [
    [0] * (W + 1) for _ in range(N + 1)
]  # flag[i][j] 表示前 i 个物品放入容量为 j 的背包最大价值时装入物品的最大编号

# dp 求解最大价值并更新 flag
for i in range(1, N + 1):
    for j in range(1, W + 1):
        if j < w[i]:
            dp[i][j] = dp[i - 1][j]
        elif dp[i - 1][j] > dp[i - 1][j - w[i]] + v[i]:
            dp[i][j] = dp[i - 1][j]
            flag[i][j] = flag[i - 1][j]
        else:
            dp[i][j] = dp[i - 1][j - w[i]] + v[i]
            flag[i][j] = i - 1
ans = dp[N][W]

# 追踪解方案
sol = [0] * N
while flag[N][W] != 0:
    temp = flag[N][W]
    sol[temp] = 1
    W -= w[temp]
    N = temp - 1

# 输出结果
print(f"最大价值为:{ans}")
print(f"取得最大价值时的物品组合为:{sol}")

结果

最大价值为:12
取得最大价值时的物品组合为:[0, 1, 0, 1]

完全背包问题

完全背包问题Unbounded Knapsack Problem)是背包问题的一种变种。其问题描述为:给定一个固定大小、能够携重 W W W 的背包,以及 N N N 个价值、重量分别为 v i v_i vi w i w_i wi 的物品,每种物品有无限件,可以选择放多少件或不放,找出一个最佳解决方案,使得装入背包的物品总重量不超过 W W W,且总价值最大。

有一个容量为 15 15 15 的背包,现有 4 4 4 个物品,其价值和重量分别为:

物品 1 2 3 4
价值 1 3 5 9
重量 2 3 4 7

求背包能装下的最大价值以及取得最大价值时的物品组合。

N = 4  # 物品数量
W = 15  # 背包容量
v = [0, 1, 3, 5, 9]  # 物品价值
w = [0, 2, 3, 4, 7]  # 物品重量
dp = [[0] * (W + 1) for _ in range(N + 1)]  # dp[i][j] 表示前 i 个物品放入容量为 j 的背包的最大价值
flag = [
    [0] * (W + 1) for _ in range(N + 1)
]  # flag[i][j] 表示前 i 个物品放入容量为 j 的背包最大价值时装入物品的最大编号

# dp 求解最大价值并更新 flag
for i in range(1, N + 1):
    for j in range(1, W + 1):
        if j >= w[i]:
            if dp[i - 1][j] < dp[i][j - w[i]] + v[i]:
                dp[i][j] = dp[i][j - w[i]] + v[i]
                flag[i][j] = i
            else:
                dp[i][j] = dp[i - 1][j]
                flag[i][j] = flag[i - 1][j]
        else:
            dp[i][j] = dp[i - 1][j]
            flag[i][j] = flag[i - 1][j]
ans = dp[N][W]

# 追踪解方案
sol = [0] * N
while flag[N][W] != 0:
    N = flag[N][W]
    sol[N - 1] = 1
    W -= w[N]
    while flag[N][W] == N:
        W = W - w[N]
        sol[N - 1] += 1

# 输出结果
print(f"最大价值为:{ans}")
print(f"取得最大价值时的物品组合为:{sol}")

结果

最大价值为:19
取得最大价值时的物品组合为:[0, 0, 2, 1]

多重背包问题

多重背包问题Bounded Knapsack Problem)是背包问题的一种变种。其问题描述为:给定一个固定大小、能够携重 W W W 的背包,以及 N N N 个价值、重量分别为 v i v_i vi w i w_i wi 的物品,每种物品有 n i n_i ni 件,可以选择放多少件或不放,找出一个最佳解决方案,使得装入背包的物品总重量不超过 W W W,且总价值最大。

有一个容量为 25 25 25 的背包,现有 4 4 4 个物品,其价值、重量、数量分别为:

物品 1 2 3 4
价值 1 3 5 9
重量 2 3 4 7
数量 5 4 3 2

求背包能装下的最大价值以及取得最大价值时的物品组合。

N = 4  # 物品数量
W = 25  # 背包容量
v = [0, 1, 3, 5, 9]  # 物品价值
w = [0, 2, 3, 4, 7]  # 物品重量
n = [0, 5, 4, 3, 2]  # 物品数量
dp = [[0] * (W + 1) for _ in range(N + 1)]  # dp[i][j] 表示前 i 个物品放入容量为 j 的背包的最大价值
flag = [
    [0] * (W + 1) for _ in range(N + 1)
]  # flag[i][j] 表示前 i 个物品放入容量为 j 的背包最大价值时装入物品的最大编号

# dp 求解最大价值并更新 flag
for i in range(1, N + 1):
    for j in range(1, W + 1):
        for k in range(min(n[i], j // w[i]) + 1):
            if dp[i][j] < dp[i - 1][j - k * w[i]] + k * v[i]:
                dp[i][j] = dp[i - 1][j - k * w[i]] + k * v[i]
                flag[i][j] = k
ans = dp[N][W]

# 追踪解方案
sol = [0] * N
j = W
for i in range(N, 0, -1):
    sol[i - 1] = flag[i][j]
    j -= flag[i][j] * w[i]
# 输出结果
print(f"最大价值为:{ans}")
print(f"取得最大价值时的物品组合为:{sol}")

结果

最大价值为:31
取得最大价值时的物品组合为:[0, 1, 2, 2]

你可能感兴趣的:(Python,算法,python,开发语言,算法)