叠甲
比较水,求轻喷
题目描述
小S在码头租用货船,有 Q 种不同类型的货船可供选择。每种货船有固定的数量 m[i]、租赁成本 v[i] 和最大载货量 w[i]。小S希望在预算 V 元内,租用能够承载最大总货物的货船组合。每种货船的具体信息包括数量、租赁价格和载货量。小S需要你帮忙计算在给定预算下,她能租用的货船的最大总载货量是多少。
Q: 货船的种类数量。V: 李华可用的总预算(单位:元)。ships: 一个列表,其中每个元素是一个元组[m[i], v[i], w[i]],分别表示第i种货船的数量、租赁价格和每艘货船的最大载货量。
思路解析
这道题是一道经典的多重背包问题。多重背包问题的基本描述是:有N个物品,每个物品i有重量w[i]和价值v[i],并且每种物品最多可以有m[i]件。背包的总容量为V。目标是选择物品装入背包,使得背包内的物品总价值最大,同时不超过背包的容量限制,并且每种物品的装入数量不能超过其上限。
一个比较简单的思路是将多重背包问题转化为0-1背包问题。即我们将选择多件第i件物品转化为,有m[i]件相同的物品,我们对每一件物品都可以选择选与不选。
在0-1背包问题中,我们最后将问题转化为对于前i件物品,我们求背包容积为j时可以达到的最大价值,可以得到的递推公式为f[i][j]=max(f[i-1][j], f[i-1][j-w[i]] + v[i])。考虑到f[i][j]的值只与前(i-1)个物品,即f[i-1]有关,因此我们可以将0-1背包问题转化为如果背包容积为j,递推公式为f[j]=max(f[j], f[j-w[i]]+v[i])。
代码
在这个多重背包问题中,我们ships[i][0]即为物品的数目,ships[i][1]即为物品的重量(这里时雇佣的费用,总容积用预算表示),ships[i][2]即为物品的价值(可载重)
根据0-1背包问题的思路,我们首先分配一个长为V+1的数组,表示总预算为下标时能载的最大重量。之后从V已知遍历到v[i],这是因为在0-1背包问题中,dp[i][j]会被dp[i][j-w[i]]影响。相当于物品i被多次放入背包。
同时我们需要考虑船的数目,我们可以从1已知遍历到m[i],表示选择船的数目的过程。当k * ships[i][1] > j或k>m[i]时,停止遍历。
由此,可以得到算法的时间复杂度为
def solution(Q, V, ships):
# Please write your code here
dp = [0] * (V + 1)
for i in range(Q):
for j in range(V, ships[i][1] - 1, -1):
for k in range(1, ships[i][0] + 1):
if k * ships[i][1] > j:
break
dp[j] = max(dp[j], dp[j - k * ships[i][1]] + k * ships[i][2])
return dp[V]
优化
接下来的是直接借鉴的内容,并没有自己实现
由于任何数字都可以转化为二进制表示法。也即
也就是说1, 2, 4, ..., 2^n可以表示一个(n+1)位的数字。我们可以将每个物品的数目按照二进制拆分,即表示为1个物品、2个物品、。。。、2^k个物品组成的物品序列。取得的物品数目即用二进制表示。
这样,将时间复杂度优化到了