题解 | 华为题库-购物单-01背包

购物单

https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4

题型:01背包变形

解题思路:

  1. 一个物品只能选一次,因此是01背包
  2. 但本题有附加条件:选择了主件才能选择附件
  3. 对每个主件,求出与其的附件搭配,将搭配后的主件看作“物品”,分别有四种情况,得到搭配后的价格与重要度 price[]、weight[]
  4. 主件
  5. 主件加附件1
  6. 主件加附件2
  7. 主件加附件1加附件2
  8. 先遍历物品,再遍历容量,由于是「一维」「01」背包,为了防止物品多次加入背包,遍历容量要倒序
  9. 尝试将搭配后的物品加入背包
  10. dp[j] = Math.max(dp[j], dp[j - price[k]] + weight[k]);

附一维背包总结规律

import java.util.Scanner;

 class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();// 容量
        int m = sc.nextInt();// 物品
        if (N <= 0 || m <= 0) {
            System.out.println(0);
            return;
        }
        Good[] goods = new Good[m + 1];
        for (int i = 1; i <= m; i++) {
            goods[i] = new Good();
        }
        for (int i = 1; i <= m; i++) {
            goods[i].price = sc.nextInt();// 价格
            goods[i].weight = sc.nextInt();// 重要度
            int owner = sc.nextInt();// 主件
            goods[i].owner = owner;
            if (owner > 0) {
                if (goods[owner].a1 == 0) {
                    goods[owner].a1 = i;
                } else {
                    goods[owner].a2 = i;
                }
            }
        }

        int[] dp = new int[N + 1];
        // 先遍历物品
        for (int i = 1; i <= m; i++) {
            if (goods[i].owner > 0) {  //当物品i是附件时,跳过
                continue;
            }
            int price[] = new int[4], weight[] = new int[4];
            //只有主件
            price[0] = goods[i].price;
            weight[0] = goods[i].price * goods[i].weight;
            //主件加附件1
            if (goods[i].a1 != 0) {
                price[1] = price[0] + goods[goods[i].a1].price;
                weight[1] = weight[0] + goods[goods[i].a1].price * goods[goods[i].a1].weight;
            }
            //主件加附件2
            if (goods[i].a2 != 0) {
                price[2] = price[0] + goods[goods[i].a2].price;
                weight[2] = weight[0] + goods[goods[i].a2].price * goods[goods[i].a2].weight;
            }
            //主件加附件1和附件2
            if (goods[i].a1 != 0 && goods[i].a2 != 0) {
                price[3] = price[0] + goods[goods[i].a1].price + goods[goods[i].a2].price;
                weight[3] = weight[0] + goods[goods[i].a1].price * goods[goods[i].a1].weight
                        + goods[goods[i].a2].price * goods[goods[i].a2].weight;
            }
            // 倒序遍历容量
            for (int j = N; j >= 1; j--) {
                for (int k = 0; k < 4; k++) {
                    // 能装下这件物品
                    if (j >= price[k] && price[k] != 0) {
                        dp[j] = Math.max(dp[j], dp[j - price[k]] + weight[k]);
                    }
                }
            }
        }
        System.out.println(dp[N]);
    }


    /**
     * 定义物品类
     */
    private static class Good {
        public int price;  //物品的价格
        public int weight;  //物品的重要度
        public int owner;  //物品的主件ID
        public int a1 = 0; //附件1ID
        public int a2 = 0; //附件2ID

    }
}
全部评论

相关推荐

02-28 17:01
门头沟学院 C++
俊朗的铁猫希望被捞:兄弟如果只想搞钱的话,你这个简历最适合的其实是辅导机构做dai写啥的真的特别赚
点赞 评论 收藏
分享
牛可乐121381:卖课的
点赞 评论 收藏
分享
评论
4
5
分享

创作者周榜

更多
牛客网
牛客企业服务