问题描述
小S在码头租用货船,有 Q 种不同类型的货船可供选择。每种货船有固定的数量 m[i]、租赁成本 v[i] 和最大载货量 w[i]。小S希望在预算 V 元内,租用能够承载最大总货物的货船组合。每种货船的具体信息包括数量、租赁价格和载货量。小S需要你帮忙计算在给定预算下,她能租用的货船的最大总载货量是多少。
Q: 货船的种类数量。V: 李华可用的总预算(单位:元)。ships: 一个列表,其中每个元素是一个元组[m[i], v[i], w[i]],分别表示第i种货船的数量、租赁价格和每艘货船的最大载货量。
测试样例
-
样例1
输入:
Q = 2,V = 10,ships = [[2, 3, 2], [3, 2, 10]]
输出:32 -
样例2
输入:
Q = 3,V = 50,ships = [[5, 10, 20], [2, 20, 30], [3, 15, 25]]
输出:100 -
样例3
输入:
Q = 1,V = 100,ships = [[10, 5, 50]]
输出:500 -
样例4
输入:
Q = 4,V = 100,ships = [[1, 100, 200], [2, 50, 100], [3, 33, 66], [4, 25, 50]]
输出:200 -
样例5
输入:
Q = 2,V = 300,ships = [[100, 1, 1], [50, 5, 10]]
输出:550
解题思路
- 明确问题为背包问题
- 该题中由于货船有多只,所以为多重背包问题。但多重背包问题本质为01背包问题,具体作法为将每种船只摊开
- 建立二维dp[i][j]数组,表示从摊开后下标为[0-i]的船只里任意取,满足最大花费小于等于j的租赁价格下,最大载货重量为多少
代码实现
第一步
将每种船只摊开。cost代表每个船只的租赁花费,value代表每个船只的载货量。这一步就相当于将多重背包问题转换为01背包。
cost, value := []int{}, []int{}
for i := 0; i < Q; i++ {
for j := 0; j < ships[i][0]; j++ {
cost = append(cost, ships[i][1])
value = append(value, ships[i][2])
}
}
第二步
初始化dp数组,由于dp[i][j]源于上一层dp[i-1][0~j]。当i为0时就需要初始化。具体为,当j<cost[0]时,dp[0][j]应该是0,因为此时不足以租赁船只。当j>=cost[0]时,dp[0][j]应该是value[0],因为此时金额可以租赁船只0。
dp := make([][]int, len(cost))
for i := range dp {
dp[i] = make([]int, V+1)
}
for i := cost[0]; i <= V; i++ {
dp[0][i] = value[0]
}
第三步
开始遍历所有船只,以及金额。此时金额与船的租赁该船的租赁价格价格会有两种关系。第一种j < cost[i],即金额小于该船的租赁价格,此时dp[i][j] = dp[i-1][j]。第二种,j >= cost[i],即金额大于该船的租赁价格,此时可以从租赁或者不租赁选择较大的一个。bigger(dp[i-1][j], dp[i-1][j-cost[i]]+value[i])。
for i := 1; i < len(cost); i++ {
for j := 0; j <= V; j++ {
if j < cost[i] {
dp[i][j] = dp[i-1][j]
} else {
dp[i][j] = bigger(dp[i-1][j], dp[i-1][j-cost[i]]+value[i])
}
}
}
第四步
返回结果
return dp[len(cost)-1][V]