Leetcode_638_大礼包_dfs

这题就离谱,剪枝反而更慢了。

这里我没有使用官方的记忆化搜索,而是通过控制选取礼包的起点,也就是函数中的那个参数st,来保证不重复选取礼包的组合,事实证明我的做法更优。

这里回溯的时候,记得要传一个new ArrayList<>(needs),不然传过去的其实是指针,会修改原来的needs,跌坑好几次了orz

思路的话没啥好说的,就是硬搜,毫无技巧可言,有点像那个完全背包。

import java.util.ArrayList;
import java.util.List;

class Solution {
    List<Integer> price;
    int len;

    List<List<Integer>> special;
    int ans = Integer.MAX_VALUE;

    public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {
        this.price = price;
        len = price.size();
        this.special = special;
        dfs(needs, 0, 0);
        return ans;
    }

    // now 为已经花费的金额
    // st 为选取st以及之后的礼包,是为了不重复选取顺序不同但礼包相同的组合
    void dfs(List<Integer> needs, int now, int st) {

        // sum为直接单买的价格
        int sum = now;
        for (int i = 0; i < len; i++) {
            sum += price.get(i) * needs.get(i);
        }

        ans = Math.min(sum, ans);

        // 各种礼包选购一遍,状态转移
        for (int i = st; i < special.size(); i++) {
            List<Integer> temp = new ArrayList<>(needs);
            List<Integer> list = special.get(i);
            boolean flag = true;
            for (int j = 0; j < len; j++) {
                int after = needs.get(j) - list.get(j);
                if (after < 0) {
                    flag = false;
                    break;
                }
                temp.set(j, after);
            }
            if (flag) {
                dfs(temp, now + list.get(len), i);
            }
        }
    }
}

减速的剪枝

// 剪枝 无用的礼包以及某个商品过多的礼包删掉
        for (List<Integer> ASpecial : special) {
            int sum = 0;
            boolean flag = true;
            for (int j = 0; j < len; j++) {
                if (ASpecial.get(j) > needs.get(j)) {
                    flag = false;
                    break;
                }
                sum += price.get(j) * ASpecial.get(j);
            }
            if (sum >= ASpecial.get(len) && flag) {
                trueSpecial.add(ASpecial);
            }
        }

        this.special = trueSpecial;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值