问题描述
在LeetCode商店中, 有许多在售的物品。
然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。
现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。
每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。
任意大礼包可无限次购买。
示例 1:
输入: [2,5], [[3,0,5],[1,2,10]], [3,2]
输出: 14
解释:
有A和B两种物品,价格分别为¥2和¥5。
大礼包1,你可以以¥5的价格购买3A和0B。
大礼包2, 你可以以¥10的价格购买1A和2B。
你需要购买3个A和2个B, 所以你付了¥10购买了1A和2B(大礼包2),以及¥4购买2A。
说明:
- 最多6种物品, 100种大礼包。
- 每种物品,你最多只需要购买6个。
- 你不可以购买超出待购清单的物品,即使更便宜。
解题报告
略。
实现代码
- DFS 另外申请变量
clone
来记录信息
class Solution {
public:
int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {
// unordered_map<vector<int>, int>mp;
return shopping(price, special, needs);
// return 0;
}
int shopping(vector<int>& price, vector<vector<int>>& special, vector<int>& needs){
// if(mp.find(needs)!=mp.end()) return mp[needs];
int i=0, ans = dot(needs, price);
for(auto item:special){
vector<int>clone(needs.begin(), needs.end());
for(i=0;i<needs.size();i++){
int diff = clone[i]-item[i];
if(diff<0) break;
else clone[i]=diff;
}
if(i==needs.size()) ans= min(ans, item[i]+shopping(price, special, clone));
}
// mp[needs]=ans;
return ans;
}
int dot(vector<int>a, vector<int>b) {
int sum = 0;
for (int i = 0; i < a.size(); i++) sum += a[i] * b[i];
return sum;
}
};
- 回溯
class Solution {
public:
int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {
//do not use coupon
int res = 0, n = price.size();
for(int i = 0; i < n;i++) {
res += price[i] * needs[i];
}
for(auto offer: special) {
bool isValid = true;
for(int j = 0; j < n;j++) {
//you cannot use this coupon
if(needs[j] < offer[j]) {
isValid = false;
}
needs[j] -= offer[j];
}
if(isValid) {
res = min(res, shoppingOffers(price,special,needs) + offer.back());
}
for(int j =0 ; j < n; j++) {
needs[j] += offer[j];
}
}
return res;
}
};
参考资料
[1] Leetcode 638. 大礼包
[2] 官方题解
[3] 评论区:Tori