贪心算法——分数背包问题

一、背景介绍

给定𝑛个物品,第𝑖个物品的重量为𝑤𝑔𝑡[𝑖−1]、价值为𝑣𝑎𝑙[𝑖−1],和一个容量为𝑐𝑎𝑝的 背包。每个物品只能选择一次,但可以选择物品的一部分,价值根据选择的重量比例计算,**问:**在不超过背包容量下背包中物品的最大价值。

如下图所示,我们可以对物品任意地进行切分,并按照重量 比例来计算物品价值。

  1. 对于物品𝑖,它在单位重量下的价值为𝑣𝑎𝑙[𝑖−1]/𝑤𝑔𝑡[𝑖−1],简称为单位价值

  2. 假设放入一部分物品𝑖,重量为𝑤,则背包增加的价值为𝑤×𝑣𝑎𝑙[𝑖−1]/𝑤𝑔𝑡[𝑖−1]。

二、具体实现

1. 贪心策略确定

最大化背包内物品总价值,本质上是要最大化单位重量下的物品价值。由此便可推出下图所示的贪心策略。

1)将物品按照单位价值从高到低进行排序。

2)遍历所有物品,每轮贪心地选择单位价值最高的物品。

3)若剩余背包容量不足,则使用当前物品的一部分填满背包即可。

2.代码实现

我们建立了一个物品类Item,以便将物品按照单位价值进行排序。循环进行贪心选择,当背包已满时跳出并 返回解。

复制代码
class Item:
    """物品"""

    def __init__(self, w: int, v: int):
        self.w = w  # 物品重量
        self.v = v  # 物品价值


def fractional_knapsack(wgt: list[int], val: list[int], cap: int) -> int:
    """分数背包:贪心"""
    # 创建物品列表,包含两个属性:重量、价值
    items = [Item(w, v) for w, v in zip(wgt, val)]
    # 按照单位价值 item.v / item.w 从高到低进行排序
    items.sort(key=lambda item: item.v / item.w, reverse=True)
    # 循环贪心选择
    res = 0
    for item in items:
        if item.w <= cap:
            # 若剩余容量充足,则将当前物品整个装进背包
            res += item.v
            cap -= item.w
        else:
            # 若剩余容量不足,则将当前物品的一部分装进背包
            res += (item.v / item.w) * cap
            # 已无剩余容量,因此跳出循环
            break
    return res


"""Driver Code"""
if __name__ == "__main__":
    wgt = [10, 20, 30, 40, 50]
    val = [50, 120, 150, 210, 240]
    cap = 50
    n = len(wgt)

    # 贪心算法
    res = fractional_knapsack(wgt, val, cap)
    print(f"不超过背包容量的最大物品价值为 {res}")

最差情况下,需要遍历整个物品列表,因此时间复杂度为𝑂(𝑛),其中𝑛为物品数量。

由于初始化了一个Item对象列表,因此空间复杂度为𝑂(𝑛)

三、正确性证明

采用反证法

假设物品𝑥是单位价值最高的物品,使用某算法求得最大价值为res,但该解中不包含物品𝑥 。 现在从背包中拿出单位重量的任意物品,并替换为单位重量的物品𝑥。由于物品𝑥的单位价值最高,因此替 换后的总价值一定大于res。这与res是最优解矛盾,说明最优解中必须包含物品𝑥。 对于该解中的其他物品,我们也可以构建出上述矛盾。总而言之,单位价值更大的物品总是更优选择,这说 明贪心策略是有效的。

如下图所示,如果将物品重量和物品单位价值分别看作一个2D图表的横轴和纵轴,则分数背包问题可被转化为"求在有限横轴区间下的最大围成面积"。这个类比可以帮助我们从几何角度理解贪心策略的有效 性。

相关推荐
Black蜡笔小新6 小时前
自动化AI算法训练服务器DLTM助力医学影像分析进入AI智能分析新时代
人工智能·算法·自动化
手写码匠7 小时前
深入解析大模型架构之争:全能通用模型 vs 领域专精模型
人工智能·深度学习·算法·aigc
浅念-7 小时前
LeetCode 回溯算法题——综合练习
数据结构·c++·算法·leetcode·职场和发展·深度优先·dfs
列星随旋8 小时前
线段树和树状数组的学习
学习·算法
全糖可乐气泡水10 小时前
Codex适配国产信创环境安装部署与技术适配全解析
开发语言·git·python·算法·百度
h_a_o777oah10 小时前
状态机+划分型 DP :深度解析K-划分问题下 DP 状态的转移逻辑(洛谷P2679 P2331 附C++代码)
c++·算法·动态规划·acm·状态机dp·划分型dp·滚动数组优化
05候补工程师10 小时前
从算法理想向工程现实的跨越:SLAM 核心架构、思维误区与 Nav2 实战避坑指南
人工智能·算法·安全·架构·机器人
手写码匠12 小时前
Android 17 适配实战指南:新特性解读、隐私变更与迁移全攻略
人工智能·深度学习·算法·aigc
珊瑚里的鱼12 小时前
leetcode42雨水
算法·leetcode