题解 | 购物单 0-1背包问题+分类讨论

购物单

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

import java.util.*;

class Good {
    int v; // 价格
    int w; // 重要度
    int q; // 主件ID 或者 附件对应的主件ID

    // 每个主件最多有2个附件
    int addition1; // 附件1
    int addition2; // 附件2

    public Good(int v, int w, int q) {
        this.v = v;
        this.w = w;
        this.q = q;
    }

    public void setAddtion1(int addition1) {
        this.addition1 = addition1;
    }

    public void setAddtion2(int addition2) {
        this.addition2 = addition2;
    }
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            // 容量为n的背包,有m个物品可选
            int n = in.nextInt(), m = in.nextInt();
            int[] v = new int[n + 1];
            int[] w = new int[n + 1];
            int[] q = new int[n + 1];
            Good[] goods = new Good[n + 1];
            for (int i = 1; i <= m; i++) {
                v[i] = in.nextInt();
                w[i] = in.nextInt();
                q[i] = in.nextInt();
                goods[i] = new Good(v[i], w[i], q[i]);
            }

            // 处理附件的归属情况
            for (int i = 1; i <= m; i++) {
                int cur = goods[i].q;
                if (cur > 0) { // cur就是主件的下标
                    if (goods[cur].addition1 > 0) { // 已经存在一个附件
                        goods[cur].setAddtion2(i);
                    } else {
                        goods[cur].setAddtion1(i);
                    }
                }
            }

            // 容量为n的背包,有m个物品可选
            // 转换成0-1背包问题:
            // 1.不选主件 2.只选主件 3.选主件和附件1 4.选主件和附件2 5.选主件、附件1和附件2
            int[][] dp = new int[m + 1][n + 1];
            for (int i = 1; i <= m; i++) {
                // 当前物品的价格和满意度(只有主件)
                int v0 = v[i], sat0 = v[i] * w[i];
                int v1 = 0, sat1 = 0;
                int v2 = 0, sat2 = 0;
                int v3 = 0, sat3 = 0;

                // 主件+附件1
                int add1 = goods[i].addition1;
                if (add1 != 0) {
                    v1 = v[add1] + v0;
                    sat1 = v[add1] * w[add1] + sat0;
                }

                // 主件+附件2
                int add2 = goods[i].addition2;
                if (add2 != 0) {
                    v2 = v[add2] + v0;
                    sat2 = v[add2] * w[add2] + sat0;
                }

                // 主件+附件1+附件2
                if (add1 != 0 && add2 != 0) {
                    v3 = v[add1] + v[add2] + v0;
                    sat3 = v[add1] * w[add1] + v[add2] * w[add2] + sat0;
                }

                // 从前i个物品中选,当前容量为j
                for (int j = 1; j <= n; j++) {
                    if (goods[i].q > 0) { // 当物品i是附件时,跳过不选
                        dp[i][j] = dp[i - 1][j];
                    } else {
                        dp[i][j] = dp[i - 1][j];
                        // v != 0这个条件是用来判断是否有附件的,是否能进行操作,如果没附件,v就是最开始初始化的0
                        if (j >= v0 && v0 != 0) {
                            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - v0] + sat0);
                        }
                        if (j >= v1 && v1 != 0) {
                            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - v1] + sat1);
                        }
                        if (j >= v2 && v2 != 0) {
                            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - v2] + sat2);
                        }
                        if (j >= v3 && v3 != 0) {
                            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - v3] + sat3);
                        }
                    }
                }
            }
            System.out.println(dp[m][n]);
        }
    }
}

全部评论

相关推荐

凉风落木楚山秋:1.教育背景,这一栏用于说明你是哪个省份的,一般四非在省内认可度是高于外省的,但是到外边了基本路边一条。然后这一栏可以写一写校内荣誉补充满一行 2.个人介绍没必要,把下面的技能内容放到这里面来,个人情况挖空等面试官来问你 3.竞赛奖项单独一栏,专门用2-3行小字写你获得了哪些奖 4.后面的模块就分为实习经历和项目经历,一个写实习做的项目,一个写学校做的项目。另外在项目中承担的角色可以标出来,时间周期也可以写一下 5.其他,你的经历和我挺像,我也大二的时候做前端,看你想找小程序还是web方向的。做小程序我感觉你这简历已经够了,比我的水货学弟强多了。要做web的话尽量再写一个react项目,不然走不远。另外,那个排课的项目看起来好水,没有亮点,可以再挖掘一下 6.名称,技术名称书写风格不统一,要么统一大驼峰,要么就用全小写+空格,保持一致好看很多
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务