算法复习——贪心策略篇之部分背包问题

算法复习——贪心策略篇之部分背包问题

以下内容主要参考中国大学MOOC《算法设计与分析》,墙裂推荐希望入门算法的童鞋学习!

1. 问题背景

调制饮品比赛

​ 参赛者拥有容量为800ml的杯子,可任选不超过体积上限的饮料进行混合,调制饮品价格为各所使用饮料的价格之和,所得饮品价格之和最高者获胜。问:如何使调制的饮品价格最高?

饮料价格(元)体积(ml)
苏打水60600
汽水10250
橙汁36200
苹果汁16100
西瓜汁45300

2. 问题定义

部分背包问题(Fractional Knapsack Problem)

输入:

  • n个物品组成的集合O,每个物品有两个属性vi和pi,分别表示体积和价格;
  • 背包容量为C。

输出:

  • 求解一个解决方法
    S = { x i ∣ 1 ≤ i ≤ n , 0 ≤ x i ≤ 1 } , S=\{x_i|1 \leq i \leq n, 0 \leq x_i \leq 1\}, S={xi1in,0xi1},
    其中,xi表示选取第i个物品的比例,使得:
    m a x ∑ x i ∈ S x i ∗ p i max \sum_{x_i \in S}x_i*p_i maxxiSxipi

    s . t . ∑ x i ∈ S x i ∗ v i ≤ C s.t.\sum_{x_i \in S}x_i*v_i \leq C s.t.xiSxiviC

    以上两式分别为优化目标和约束条件。

3. 贪心策略

​ 这个问题十分简单,大家简单思考一下就知道,只要最高性价比优先,就可以得到最优解(性价比=价格/体积)。最优解即优先选择高性价比饮料全部装入,尽可能装满杯子。

​ 首先计算各种饮料的性价比:

饮料价格(元)体积(ml)性价比(元/ml)
苏打水606000.10
汽水102500.04
橙汁362000.18
苹果汁161000.16
西瓜汁453000.15

​ 然后将各种饮料的性价比进行排序,尽可能用当前性价比最高的饮料去装入杯子,解决方案即为

饮料价格(元)体积(ml)
橙汁36200
苹果汁16100
西瓜汁45300
苏打水20200

4. 正确性证明

贪心策略的想法有时十分容易想到,但关键在于证明为什么这个贪心策略能够得到最优解。贪心策略证明最常用的方法是替换法,即假设存在另外的一个最优解,并且通过有限的步骤,可以替换成贪心策略得到的解,从而证明贪心解就是最优解。

​ 本题的贪心策略是最高性价比优先,需要证明的是贪心解不劣于最优解

​ 假设存在另一个最优解,记为S*,贪心解记为S。首先,最优解和贪心解肯定都会装满,在装满后,我们可以按照性价比递减将饮料在杯子中排好顺序。同时对于贪心解,
x i ′ = 1 ,      i f   i = 1 , 2 , ∣ S ′ ∣ − 1 ; x^{'}_{i}=1,\ \ \ \ if\ i = 1, 2, |S^{'}|-1; xi=1,    if i=1,2,S1;

x ∣ S ′ ∣ ′ ≤ 1. x^{'}_{|S^{'}|} \leq 1. xS1.

在这里插入图片描述

​ 假设我们前i-1种都放了性价比最高的饮料且放的量一样多(即贪心解和最优解目前相同),但是在放第i种饮料时出现了不同。在贪心解中,第i种饮料应该放置的是性价比第i高的饮料,而且在不超过杯子容量的情况下,尽可能全部加进去;如果最优解不同于贪心解的话,只能是最优解中第i种饮料不是贪心解中的第i种饮料,或者最优解中第i种饮料是贪心解中的第i种饮料,但是其最优解放的量小于贪心解放的量这两种情况。可以用下图表示。

在这里插入图片描述

​ 假设是后者的情况,即装了一部分第i种饮料,但没有把第i种饮料全部加入的情况(前者的情况本质上同理),那我们可以把最优解中第i种后面的饮料(即下图中红框的部分)换成第i种饮料,使第i种饮料全部加入。易证这样替换后总价值不会减少,因为我们是按照性价比递减的顺序向上装饮料,那么在相同体积下,蓝色这部分饮料的价格一定低于替换为第i种饮料的价格。

在这里插入图片描述

​ 后面的情况便可以依次类推,遇到不同的情况,就用相同的方法去替换,显然替换后单位体积价值均不减少。全部替换完毕后,最优解就变成了贪心解,贪心解不劣于最优解得证。

​ 根据假设,最优解已经是最优的情况,贪心解不劣于最优解,那么贪心解就是最优解。

5. 伪代码

FractionalKnapsack(n, p, v, C)

输入:商品数量n,各商品的价值p,各商品的体积v,背包容量C

输出:商品价值的最大值,最优解方案

计算商品性价比Ratio[1..n]并按降序排序
// Ratio[i], p[i], v[i]分别表示性价比第i大的商品的性价比、价格和体积
i <- 1
ans <- 0
// 根据贪心策略求解
while C > 0 and i <= n do
	if v[i] <= C then
		选择商品i
		ans <- ans + p[i]
		C <- c - V[i]
	end
	else
		选择C体积的商品i
		ans <- ans + p[i]*(C/v[i])
		C <- 0
	end
	i <- i + 1
end
return ans

时间复杂度分析

​ 按性价比排序的时间复杂度是O(n log n),通过贪心策略遍历物品的时间复杂度是O(n),所以整体算法的时间复杂度是O(n log n)。

6. 贪心策略:一般步骤

这个问题虽然简答,但是我们可以从中提取出贪心策略的一般步骤。

  1. 提出贪心策略:观察问题特征,构造贪心选择;
  2. 证明策略正确:假设最优方案,通过替换证明。

7. 相关例题

洛谷 P2676 [USACO07DEC]Bookshelf B

洛谷 P2240 【深基12.例1】部分背包问题

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值