啊,告别ACM已经两三年了吧,最近朋友又时不时的发一些题目给我,手痒的做了做,想不起C++语法边写边查也是很坑。。。
题目的传送门:638. 大礼包
这题应该搜索也可以过,朋友想让我用dp解,刚开始因为姿势不对,算了很多没有意义的数据,一直超时,后面改成记忆化搜索好了很多,另,本来第一次是20ms,更改为动态数组之后,变成了4ms,打败了98%的人,瞬间,我又回忆起了被memset支配的恐惧。。。果然大数组memset还是很耗时的。
代码如下啦,类似背包的解题思路,只是多了可不可以买这样一个判断,由于每种物品最大是6个,物品种类最大也是6,因此状态的话可以看成是不超过666666的一个数字,然后从目标反向搜索就好啦。
class Solution {
private:
int *dp;
bool can_buy(vector<int>& special, string& needs, int kind){
bool flag = true;
for(int i = 0;i < special.size() - 1; i ++){
if(needs[i]- 48 < special[i]){
flag = false;
break;
}
}
return flag;
}
int max_cost(string& aim, vector<int>& price){
int cost = 0;
for(int i = 0;i < aim.length(); i ++){
cost += price[i] * (aim[i] - 48);
}
return cost;
}
int cal_last_key(int current, vector<int>& v){
int res = 0;
for(int i = 0; i < v.size() - 1; i ++){
res *= 10;
res += v[i];
}
return current - res;
}
int shopping(int target, vector<vector<int> >& special, vector<int>& price){
if(target == 0){
return 0;
}
if(dp[target] != -1) {
return dp[target];
}
string t_s = to_string(target);
int kind = price.size();
while(t_s.length() < kind){
t_s = '0' + t_s;
}
int cost = max_cost(t_s, price);
for(int j = 0; j < special.size(); j ++){
// current special more than needs
if(!can_buy(special[j], t_s, kind)){
continue;
}
int current_key = target;
int last_key = cal_last_key(target, special[j]);
cost = min(cost, shopping(last_key, special, price) + special[j][kind]);
}
return dp[target] = cost;
}
public:
int shoppingOffers(vector<int>& price, vector<vector<int> >& special, vector<int>& needs) {
// get tagert needs
int target = 0;
for(int i = 0; i < needs.size(); i ++){
target *= 10;
target += needs[i];
}
int t[target + 1];
dp = t;
memset(t, -1, sizeof(t));
dp[0] = 0;
return shopping(target, special, price);
}
};