java——HJ16 购物单 0-1背包问题 动态规划

题目描述(复制过来的)

王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件附件
电脑打印机,扫描仪
书柜图书
书桌台灯,文具
工作椅

如果要买归类为附件的物品,必须先买该附件所属的主件,且每件物品只能购买一次。

每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。

王强查到了每件物品的价格(都是 10 元的整数倍),而他只有 N 元的预算。除此之外,他给每件物品规定了一个重要度,用整数 1 5 表示。他希望在花费不超过 N 元的前提下,使自己的满意度达到最大。

满意度是指所购买的每件物品的价格与重要度的乘积的总和,假设设第ii件物品的价格为v[i]v[i],重要度为w[i]w[i],共选中了kk件物品,编号依次为j_1,j_2,...,j_kj1​,j2​,...,jk​,则满意度为:v[j_1]*w[j_1]+v[j_2]*w[j_2]+ … +v[j_k]*w[j_k]v[j1​]∗w[j1​]+v[j2​]∗w[j2​]+…+v[jk​]∗w[jk​]。(其中 * 为乘号)

请你帮助王强计算可获得的最大的满意度。

输入描述:

输入的第 1 行,为两个正整数N,m,用一个空格隔开:

(其中 N ( N<32000 )表示总钱数, m (m <60 )为可购买的物品的个数。)

从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q

(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)

输出描述:

 输出一个正整数,为张强可以获得的最大的满意度。

示例1

输入:

1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

输出:

2200

复制

示例2

输入:

50 5
20 3 5
20 3 5
10 3 0
10 2 0
10 1 0

输出:

130

解题思路:

       解这道题必须了解0-1背包问题(可以在b站搜索了解一下)。对于0-1背包问题,考虑物品i时,若背包容量足够加入物品i,只需要比较不加入物品i的价值与预留物品i容量后背包最大价值+物品i价值哪个更大。

                                f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

其中f[i−1][j−w[i]]为预留物品i后的最大价值,v[i]为物品i价值

这道题在0-1背包问题的基础上加入了附件的概念,只有购买了主物件才能购买附件。以题目表述的示例1为例,2 3是附件,1 4 5是主件。附件不单独考虑,附件应该作为背包容量增加时,主件是否加入背包的子问题,借用一张图来说明问题:

 当背包容量足够加入物品i和物品i的附件1,附件2时,考虑物品i(主件)是否加入背包的情况分为:

1. 不加入物品i :        

                        f[i−1][j]

2. 预留物品i的空间,加入物品i:       

                         ​f[i−1][j-weight[i]]+value[i] ​

3. 预留物品i与附件1(o1)的空间加入物品i和附件1:        

                         f[i−1][j-weight[i]-weight[o1]]+value[i]+value[o1]

4. 预留物品i与附件2(o2)的空间加入物品i与附件2:

                          f[i−1][j-weight[i]-weight[o2]]+value[i]+value[o2]

5. 预留物品i与附件1,2的空间加入物品i与附件1,2

                          f[i−1][j-weight[i]-weight[o2]-weight[o1]]+value[i]+value[o2]+value[o1]

f[i][j]为以上五种情况的最大值(仅考虑背包容量足够加入物品i和物品i的附件1,附件2时),若背包容量只能放入物品i和附件1,只需要考虑情况1 2 3,比较这三种情况

代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class Beibao {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        String[] strings = s.split(" ");
        int money = Integer.parseInt(strings[0]);
        int num = Integer.parseInt(strings[1]);
        List<God> godList = new ArrayList<>();
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            String s1 = in.nextLine();
            String[] strings1 = s1.split(" ");
            God god = new God(Integer.parseInt(strings1[0]),Integer.parseInt(strings1[1]),Integer.parseInt(strings1[2]));
            godList.add(god);
        }
        for (int i = 0; i < godList.size(); i++) {
            God god = godList.get(i);
            if (!(god.getBelong()==0)){
                List<God> godList1 = godList.get(god.getBelong() - 1).getGodList();
                if (godList1!=null){
                    godList1.add(god);
                }else {
                    godList1 = new ArrayList<>();
                    godList1.add(god);
                    godList.get(god.getBelong() - 1).setGodList(godList1);
                }
            }
        }
        int ll = godList.size();
        for (int i = 0; i < ll; i++){
            God god = godList.get(i);
            if (god.getBelong()!=0){
                godList.remove(i);
                i--;
                ll--;
            }
        }
        int[][] dp  = new int[godList.size()+1][money/10+1];
        for (int i = 0; i <= godList.size(); i++) {

            for (int j = 0; j <= money/10; j++) {

                if (i==0){
                    dp[i][j] = 0;
                }else {
                    God god = godList.get(i-1);
                    int godMoney = god.getP();
                    int godImp = god.getV();
                    int value = godMoney*godImp;
                    List<God> childList = god.getGodList();
                    int f1Money = 0;
                    int f1Imp = 0;
                    int f2Money = 0;
                    int f2Imp = 0;
                    if (childList!=null){
                        for (int k = 0; k < childList.size(); k++) {
                            if (k==0){
                                f1Money = childList.get(k).getP();
                                f1Imp = childList.get(k).getV();
                            }
                            if (k==1){
                                f2Money = childList.get(k).getP();
                                f2Imp = childList.get(k).getV();
                            }
                        }
                    }
                    int value1 = f1Imp*f1Money;
                    int value2 = f2Money*f2Imp;
                    if (j*10<godMoney){
                        dp[i][j] = dp[i-1][j];
                        continue;
                    }
                    if (f1Money>f2Money){
                        if (j*10<f2Money+godMoney){
                            // 只能选物品i或不选
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value);
                        }else if (j*10>=f2Money+godMoney&&j*10<f1Money+godMoney){
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value,dp[i-1][j-godMoney/10-f2Money/10]+value+value2);
                            // 只能选物品i+便宜附件附件
                        }else if (j*10>=godMoney+f1Money&& j*10<godMoney+f1Money+f2Money){
                            // 物品i 只能选一个附件
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value,dp[i-1][j-godMoney/10-f2Money/10]+value+value2,dp[i-1][j-godMoney/10-f1Money/10]+value+value1);
                        }else {
                            // 可以选
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value,dp[i-1][j-godMoney/10-f2Money/10]+value+value2,dp[i-1][j-godMoney/10-f1Money/10]+value+value1,dp[i-1][j-godMoney/10-f1Money/10-f2Money/10]+value+value1+value2);
                        }
                    }else {
                        if (j*10<f1Money+godMoney){
                            dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-godMoney/10]+value);
                        }else if (j*10>=f1Money+godMoney&&j*10<f2Money+godMoney){
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value,dp[i-1][j-godMoney/10-f1Money/10]+value+value1);
                        }else if(j*10>=godMoney+f2Money&& j*10<godMoney+f1Money+f2Money){
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value,dp[i-1][j-godMoney/10-f2Money/10]+value+value2,dp[i-1][j-godMoney/10-f1Money/10]+value+value1);
                        }else {
                            dp[i][j] = myMax(dp[i-1][j],dp[i-1][j-godMoney/10]+value,dp[i-1][j-godMoney/10-f2Money/10]+value+value2,dp[i-1][j-godMoney/10-f1Money/10]+value+value1,dp[i-1][j-godMoney/10-f1Money/10-f2Money/10]+value+value1+value2);
                        }
                    }

                }
            }
        }

        System.out.println(dp[godList.size()][money/10]);

    }

    private static int myMax(int...a) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (int i:a
             ) {
            arrayList.add(i);
        }
        Collections.sort(arrayList);
        return arrayList.get(arrayList.size()-1);
    }
}

class God{
    private int p;
    private int v;
    private int belong;
    private List<God> godList;

    public God(int p, int v, int belong) {
        this.p = p;
        this.v = v;
        this.belong = belong;
    }

    @Override
    public String toString() {
        return "God{" +
                "p=" + p +
                ", v=" + v +
                ", belong=" + belong +
                ", godList=" + godList +
                '}';
    }

    public God() {
    }

    public int getP() {
        return p;
    }

    public void setP(int p) {
        this.p = p;
    }

    public int getV() {
        return v;
    }

    public void setV(int v) {
        this.v = v;
    }

    public int getBelong() {
        return belong;
    }

    public void setBelong(int belong) {
        this.belong = belong;
    }

    public List<God> getGodList() {
        return godList;
    }

    public void setGodList(List<God> godList) {
        this.godList = godList;
    }
}

结果:

总结:

        本题需要把物品i附件作为物品i是否加入背包的子问题,所以需要考虑的情况比较多,考虑清楚就能解决问题。

        

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
hj30j-36-21629dl规格书是指一份关于hj30j-36-21629dl产品的详细说明文档。规格书是为了让用户、工程师、设计师等对产品的性能、功能、尺寸、材料、工艺等方面有一个清晰的了解。 首先,规格书通常包括产品的基本信息,如产品名称、型号、生产厂商等。这些信息有助于准确识别和辨别产品。 其次,规格书还会详细列出产品的技术参数和性能指标,包括电气参数、机械参数、环境要求等。例如,电气参数可能包括额定电压、额定电流、功率因数等;机械参数可能包括尺寸、重量、外观要求等。这些参数和指标对于用户选择合适的产品,以及工程师进行设计和安装工作非常重要。 此外,规格书还会介绍产品的功能特点和应用范围。产品的功能特点是指产品所具备的一些特殊功能或优势,例如高效节能、可靠性强等。应用范围则是指产品适用的场景和领域,例如工业自动化、建筑电力等。 最后,规格书会包含产品的质量保证、安全要求、以及维护保养等方面的描述。这些内容有助于用户正确使用产品,延长产品的使用寿命,同时确保使用过程中的安全性。 总之,hj30j-36-21629dl规格书是一份关于该产品的详细说明文档,旨在提供给用户、工程师、设计师等相关人员有关该产品的详细信息,以便他们进行选型、设计、安装、使用和维护等工作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值