Leetcode 638. 大礼包 dp解法

啊,告别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);
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值