1. 部分背包问题解析与贪心算法实现
作为一名算法竞赛选手,我经常遇到背包问题的各种变种。今天要讨论的部分背包问题(Fractional Knapsack Problem)是其中最基础也最实用的一个版本。与0-1背包不同,它允许物品被分割,这使得贪心算法成为可能。下面我将详细解析这个问题,并分享我的解题思路和代码实现经验。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 问题理解与建模
2.1 问题描述重述
阿里巴巴进入藏宝洞,发现N堆金币(N≤100),每堆金币有重量mᵢ和价值vᵢ(1≤mᵢ,vᵢ≤100)。他有一个承重为T(T≤1000)的背包,可以带走部分金币堆(可以分割)。目标是最大化带走金币的总价值。
关键点:
- 金币可以分割(与0-1背包问题不同)
- 需要计算单位重量的价值(性价比)
- 输出保留两位小数
2.2 问题特性分析
部分背包问题的特殊性质决定了它的解法:
- 可分性:物品可以按任意比例分割
- 局部最优性:当前最优选择能导致全局最优解
- 无后效性:选择不影响后续决策
这些特性使得贪心算法成为解决此问题的理想选择。
3. 贪心算法设计
3.1 算法核心思想
贪心策略的本质是:每次选择当前看来最优的选择。对于部分背包问题,最优策略是:
- 计算每堆金币的单位价值(vᵢ/mᵢ)
- 按单位价值从高到低排序
- 依次装入背包,能装整堆就全装,不能装就装部分
3.2 数学证明
为什么这个策略能得到最优解?我们可以用交换论证法证明:
假设存在一个最优解O与我们的贪心解G不同。找到第一个不同的选择点,在这一点上O选择了单位价值较低的金币。我们可以用G的选择替换O的选择,这样总价值不会减少(因为G选择的是单位价值更高的)。重复这个过程,最终O会被转化为G,且总价值不会降低。
4. 代码实现详解
4.1 数据结构设计
cpp复制struct GoldPile {
double m; // 重量
double v; // 价值
};
使用结构体存储每堆金币的重量和价值,方便后续处理。注意使用double类型以支持分割计算。
4.2 关键算法步骤
- 输入处理:
cpp复制cin >> n >> t;
go
