题目
知识点
思路
- 我们把当前购买数量情况作为状态,那我们要求的就是满足题意下使得我们的价格最低,那么状态转移方程就是:
当前状态的最小价格 = min((满足条件的情况n状态的最小价格)+ 情况n的价格))
- 上述转移方程中的满足条件情况分两种:
- 有special大礼包可以选择,即大礼包中的每一项数量都小于目前需要的数量(注意:是当前需要的数量,Line 9:
choice[i] > ed[i] - status[i]
),写了一个 check()
进行判断 - 直接不选大礼包,计算当前状态单买的价格,因为在测试数据里有单买比大礼包还便宜的情况!(就离谱…),因此情况1递归返回以后的结果取最小以后,还要和这个情况比较一下,选择最小的返回当前状态的结果,并保存在
map<vector<int>, int> m
中(这个状态用的 vector
保存,所以我直接用了一个 vector->int
的 map
)。
代码
- Line 45 - 51 行的代码照理来说可以与 Line 37-41 合并,但是合并以后有一组数据一直过不了QAQ,整体的时间效率有待提高(当然比不用记忆化搜索(dp)方式还是快上不少的)
class Solution {
public:
map<vector<int>, int> m;
vector<int> p, ed;
vector<vector<int>> sp;
bool check(vector<int> status, vector<int> choice) {
for (int i = 0; i < status.size(); i++) {
if (choice[i] > ed[i] - status[i]) {
return false;
}
}
return true;
}
vector<int> update(vector<int> status, vector<int> choice) {
for (int i = 0; i < status.size(); ++i) {
status[i] += choice[i];
}
return status;
}
int dfs(const vector<int> &status, int current) {
if (m.count(status)) return m[status];
int ans = 1e9;
bool is_ok = false;
for (const vector<int> &choice:sp) {
if (check(status, choice)) {
int price = choice[choice.size() - 1];
is_ok = true;
vector<int> status_new = update(status, choice);
ans = min(ans, dfs(status_new, current + price) + price);
int sum = 0;
for (int i = 0; i < status_new.size(); i++) {
sum += (ed[i] - status_new[i]) * p[i];
}
ans = min(ans, current + price + sum);
}
}
if (!is_ok) {
int sum = 0;
for (int i = 0; i < status.size(); i++) {
sum += (ed[i] - status[i]) * p[i];
}
return sum;
}
m[status] = ans;
return ans;
}
int shoppingOffers(vector<int> &price, vector<vector<int>> &special, vector<int> &needs) {
p = price, ed = needs, sp = special;
int direct = 0;
for (int i = 0; i < ed.size(); i++) {
direct += (ed[i]) * p[i];
}
return min(direct, dfs(vector<int>(needs.size(), 0), 0));
}
};