一、题目描述:
leetcode-cn.com/problems/sh…
现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。
每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。
任意大礼包可无限次购买。
****示例 1:
输入: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]
输出: 11
解释:
A,B,C的价格分别为¥2,¥3,¥4.
你可以用¥4购买1A和1B,也可以用¥9购买2A,2B和1C。
你需要买1A,2B和1C,所以你付了¥4买了1A和1B(大礼包1),以及¥3购买1B, ¥4购买1C。
你不可以购买超出待购清单的物品,尽管购买大礼包2更加便宜。
二、思路分析:
- 递归 + dfs
- 递归函数定义为当前还剩余需要买的物品最少花的钱.
- 首选从购买礼包套餐,若是购买礼包套餐后,剩余还需要购买的物品不为负数,则这个方案是可行的继续递归购买剩下的物品.
三、AC 代码:
/**
* @param {number[]} price
* @param {number[][]} special
* @param {number[]} needs
* @return {number}
*/
var shoppingOffers = function(price, special, needs) {
function dfs(lefted){
let min = getMoney(lefted)
for(let i=0;i<special.length;i++){
const spOffer = special[i]
const leftedNeeds = canBuySpOffer([...lefted],spOffer)
if(leftedNeeds.length){
const res = dfs([...leftedNeeds])
min = Math.min(min,res + spOffer[spOffer.length-1])
}
}
return min
}
function canBuySpOffer(lefted,special){
for(let i=0;i<lefted.length;i++){
const diff = lefted[i] - special[i]
lefted[i] = diff
if(diff<0){
return []
}
}
return lefted
}
function getMoney(lefted){
let sum = 0
for(let i=0;i<lefted.length;i++){
sum += lefted[i] * price[i]
}
return sum
}
return dfs(needs)
};
四、总结:
- 抓住核心,即状态转移