首页 > 试题广场 >

购物单

[编程题]购物单
  • 热度指数:452811 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅
如果要买归类为附件的物品,必须先买该附件所属的主件,且每件物品只能购买一次。
每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。
王强查到了每件物品的价格(都是 10 元的整数倍),而他只有 N 元的预算。除此之外,他给每件物品规定了一个重要度,用整数 1 ~ 5 表示。他希望在花费不超过 N 元的前提下,使自己的满意度达到最大。
满意度是指所购买的每件物品的价格与重要度的乘积的总和,假设设第i件物品的价格为,重要度为,共选中了k件物品,编号依次为j_1,j_2,...,j_k,则满意度为:。(其中 * 为乘号)
请你帮助王强计算可获得的最大的满意度。




输入描述:
输入的第 1 行,为两个正整数N,m,用一个空格隔开。其中 N 表示总钱数, m 为可购买的物品的个数。
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v、p、q。
其中 v 表示该物品的价格,p 表示该物品的重要度,q 表示该物品是主件还是附件。
如果 q=0,表示该物品为主件,如果q>0,表示该物品为附件, q 是所属主件的编号。

数据范围:N<32000,m<60,v<10000,1<=p<=5。


输出描述:
 输出一个正整数,为张强可以获得的最大的满意度。
示例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

说明

由第1行可知总钱数N为50以及希望购买的物品个数m为5;
第2和第3行的q为5,说明它们都是编号为5的物品的附件;
第4~6行的q都为0,说明它们都是主件,它们的编号依次为3~5;
所以物品的价格与重要度乘积的总和的最大值为10*1+20*3+20*3=130       
让dp[j]表示为: 预算为j元的情况下,能买到的最大满意度。
遍历所有主件(循环A)
在循环A内 遍历所有金额 (从M到1反着遍历目的是不重复买入)
面对每个主件商品的每个预算下的最大满意度dp[i],我们只有四种情况需要考虑
①要不要买主件
②要不要买主件+附件1
③要不要买主件+附件2
④要不要买主件+附件1+附件2

注意: 除非是附件不够,那么23或4可能不会考虑,除此之外每一种情况都要去计算,原因是1234各种情况的更新来源都是不同的,很有可能买主件+附件1反而比买主件+附件1+附件2有更大的满意度,这是因为,决定满意度的不只是当前主件和附件的满意度,还要受你的参考来源决定。
参考来源意思就是 你如果选择买500块的东西 那么你的参考来源就是dp[i-500],不同的价格参考来源是不同的

这样一来就能在遍历完所有主件后,拿到从M到0元预算下,各个预算能买到的最大满意度.
import java.util.ArrayList;
import java.util.Scanner;

/**
 * Description:
 * Author: fy
 * Date: 2024/11/14 7:21
 */

public class Main {

    static class Products {
        int price;
        int important;
        int index;

        public Products(int price, int important, int index) {
            this.price = price;
            this.important = important;
            this.index = index;

        }

        @Override
        public String toString() {
            return "价格:" + price + " 重要度:" + important + " 索引:" + index;
        }
    }

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        String[] split = s.split(" ");
        int amount = Integer.parseInt(split[0]);
        int productCount = Integer.parseInt(split[1]);


        ArrayList<Products> mainList = new ArrayList<>();
        ArrayList<ArrayList<Products>> attachList = new ArrayList<>();
        for (int i = 0; i < productCount; i++) {
            attachList.add(new ArrayList<>());

        }
        int record = 0;
        for (int i = 0; i < productCount; i++) {
            String proStr = in.nextLine();
            String[] proSplit = proStr.split(" ");
            int price = Integer.parseInt(proSplit[0]);
            int important = Integer.parseInt(proSplit[1]);
            int mainProductIndex = Integer.parseInt(proSplit[2]);
            int index = record;

            if (mainProductIndex == 0) {
                //存主件
                Products products = new Products(price, important, index);
                mainList.add(products);
            } else {
                //存附件
                if (attachList.get(mainProductIndex - 1) == null) {
                    attachList.set(mainProductIndex - 1, new ArrayList<>());
                }
                Products products = new Products(price, important, index);
                attachList.get(mainProductIndex - 1).add(products);
            }
            record++;
        }

        int[] dp = new int[amount + 1];
        dp[0] = 0;

        for (int i = 0; i < mainList.size(); i++) {
            Products products = mainList.get(i);
            int price = products.price;
            int important = products.important;
            int index = products.index;

            for (int j = amount; j > 0; j--) {
                //如果为空只考虑加或不加主件
                if (attachList.get(index).isEmpty()) {
                    if (j >= price) {
                        dp[j] = Math.max(dp[j], dp[j - price] + important * price);
                    }
                } else {
                    //如果有附件 先看看存不存主件
                    if (j >= price) {
                        dp[j] = Math.max(dp[j], dp[j - price] + important * price);
                    }
                    //在分别考虑 主件+附件1 和 主件+附件2  要不要为dp[j构成满意度
                    for (int k = 0; k < attachList.get(index).size(); k++) {
                        Products attachProducts = attachList.get(index).get(k);
                        int attachPrice = attachProducts.price;
                        int attachImportant = attachProducts.important;

                        if (j >= price + attachPrice) {
                            dp[j] = Math.max(dp[j], dp[j - price - attachPrice] + important * price +
                                             attachImportant * attachPrice);
                        }
                    }
                    //如果有两个附件 还要考虑主件+两个附件 要不要为dp[j]构成满意度
                    if (attachList.get(index).size() > 1) {
                        Products attachProducts1 = attachList.get(index).get(0);
                        int attachPrice1 = attachProducts1.price;
                        int attachImportant1 = attachProducts1.important;
                        Products attachProducts2 = attachList.get(index).get(1);
                        int attachPrice2 = attachProducts2.price;
                        int attachImportant2 = attachProducts2.important;
                        int sumPrice = price + attachPrice1 + attachPrice2;
                        int sumImportant = important * price + attachImportant1 * attachPrice1 +
                                           attachImportant2 * attachPrice2;
                        if (j >= sumPrice) {
                            dp[j] = Math.max(dp[j], dp[j - sumPrice] + sumImportant);
                        }
                    }
                }
            }
        }
        System.out.println(dp[amount]);
    }
}






发表于 2024-11-16 00:34:34 回复(0)

这是一个典型的0-1 背包问题的变种,其中存在主件和附件的约束关系。我们需要使用动态规划来解决这个问题。

问题分析

  1. 主件和附件的关系:

    • 物品可以是主件(q = 0)或附件(q > 0)。
    • 如果物品是附件,则必须购买其所属的主件才能购买该附件。
  2. 目标:

    • 在不超过预算N的前提下,选择购买物品使得总满意度(价格乘以重要度的和)最大。
  3. 思路:

    • 将每个主件和它的附件组合视为一个整体,考虑如何购买这些组合来获得最大满意度。
    • 使用动态规划来解决这个多重背包问题。
    • package com.shisui.medium;
      import java.util.*;
      public class shopping_list {
      
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              int N = sc.nextInt(); // 总钱数
              int m = sc.nextInt(); // 物品个数
              int[] dp = new int[N + 1]; // dp数组,dp[j]表示总价不超过j时的最大满意度
      
              // 物品信息
              Item[] items = new Item[m + 1];
              List<Item>[] attachments = new List[m + 1];
      
              // 初始化
              for (int i = 0; i <= m; i++) {
                  attachments[i] = new ArrayList<>();
              }
      
              // 读取物品数据
              for (int i = 1; i <= m; i++) {
                  int v = sc.nextInt();
                  int p = sc.nextInt();
                  int q = sc.nextInt();
                  items[i] = new Item(v, p, q);
                  if (q > 0) {
                      attachments[q].add(items[i]); // 把附件添加到对应的主件附件列表中
                  }
              }
      
              // 动态规划求解
              for (int i = 1; i <= m; i++) {
                  if (items[i].q > 0) continue; // 处理附件时跳过
                  for (int j = N; j >= 0; j--) { // 从总钱数开始倒序遍历
                      // 主件选项
                      if (j >= items[i].v) {
                          dp[j] = Math.max(dp[j], dp[j - items[i].v] + items[i].v * items[i].p);
                      }
                      // 主件+附件1选项
                      if (attachments[i].size() >= 1 && j >= items[i].v + attachments[i].get(0).v) {
                          dp[j] = Math.max(dp[j], dp[j - items[i].v - attachments[i].get(0).v]
                                  + items[i].v * items[i].p
                                  + attachments[i].get(0).v * attachments[i].get(0).p);
                      }
                      // 主件+附件2选项
                      if (attachments[i].size() == 2 && j >= items[i].v + attachments[i].get(1).v) {
                          dp[j] = Math.max(dp[j], dp[j - items[i].v - attachments[i].get(1).v]
                                  + items[i].v * items[i].p
                                  + attachments[i].get(1).v * attachments[i].get(1).p);
                      }
                      // 主件+附件1+附件2选项
                      if (attachments[i].size() == 2 && j >= items[i].v + attachments[i].get(0).v + attachments[i].get(1).v) {
                          dp[j] = Math.max(dp[j], dp[j - items[i].v - attachments[i].get(0).v - attachments[i].get(1).v]
                                  + items[i].v * items[i].p
                                  + attachments[i].get(0).v * attachments[i].get(0).p
                                  + attachments[i].get(1).v * attachments[i].get(1).p);
                      }
                  }
              }
              System.out.println(dp[N]);
          }
      
          // 定义一个Item类来存储物品信息
          static class Item {
              int v; // 价格
              int p; // 重要度
              int q; // 0表示主件,其他表示附件所属主件的编号
      
              public Item(int v, int p, int q) {
                  this.v = v;
                  this.p = p;
                  this.q = q;
              }
          }
          }
      
      


发表于 2024-09-13 15:06:05 回复(0)
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        //看了好些回答,都是用动态规划来解决,可惜没看懂
        //主要是为啥双重循环要用金额的递增,所以就用了自己的
        //土办法,发出来,看看对不对
        //没提交通过,因为有个预期输出,我感觉它给的不对,所以无法判断我这个方法的正确性
        Scanner in = new Scanner(System.in);
        String first = in.nextLine();
        int n = Integer.parseInt(first.split(" ")[0]);
        int m = Integer.parseInt(first.split(" ")[1]);
        List<List<Integer>> list = new ArrayList<>();
        // 不想建实体类,就偷懒用list包裹list来获取数据
        while (in.hasNextLine()) {
            List<Integer> t = new ArrayList<>();
            String input = in.nextLine();
            t.add(Integer.parseInt(input.split(" ")[0]));
            t.add(Integer.parseInt(input.split(" ")[1]));
            t.add(Integer.parseInt(input.split(" ")[2]));
            list.add(t);
        }
        int result = 0;
        //循环输入的行数,就是依次从行数来开始购物,如第一次从第一行开始买,钱还有,接着第二行,如果第二行超出,
        //接着第三行这样
        for (int i = 0; i < list.size(); i++) {
            //记录每次购买的编号,主要是主件要不要重新计算
            List<Integer> temp = new ArrayList<>();
            int num = 0;//每次购买后满意度,每一次大循环重置
            int out = calc(n, m, i, list, num, temp);
            if (out > result) {//看看每次的循环的最大值
                result = out;
            }
        }
        System.out.println(result);
        in.close();
    }

    private static Integer calc(int n, int m, int i, List<List<Integer>> list,
                                 int result, List<Integer> have) {
        if (m < 0) {
            return result;
        }
        if (have.contains(i)) {
            //如果已经计算就下一行
            if (i < list.size() - 1) {
                return calc(n, m, i + 1, list, result, have);
            } else {
                return result;
            }
        }
        List<Integer> temp = list.get(i);
        int v = temp.get(0);
        int p = temp.get(1);
        int q = temp.get(2);
        if (q == 0) {//主件直接计算
            if (v > n) {
                if (i < list.size() - 1) {
                    return calc(n, m, i + 1, list, result, have);
                } else {
                    return result;
                }
            }
            have.add(i);//记录已经算过的编号
            int j = v * p;
            result += j;
            if (i < list.size() - 1) {
                return calc(n - v, m - 1, i + 1, list, result, have);
            } else {
                return result;
            }
        } else {
            //附件先看主件有没有计算过
            if (have.contains(q - 1)) {
                if (v > n) {
                    if (i < list.size() - 1) {
                        return calc(n, m, i + 1, list, result, have);
                    } else {
                        return result;
                    }
                }
                have.add(i);
                int j = v * p;
                result += j;
                return calc(n - v, m - 1, i + 1, list, result, have);
            } else {
                List<Integer> temp2 = list.get(q - 1);
                int v1 = temp2.get(0);
                int p1 = temp2.get(1);
                if (v1 + v > n) {
                    if (i < list.size() - 1) {
                        return calc(n, m, i + 1, list, result, have);
                    } else {
                        return result;
                    }
                }
                have.add(q - 1);
                int j = v * p + v1 * p1;
                result += j;
                if (i < list.size() - 1) {
                    return calc(n - v - v1, m - 2, i + 1, list, result, have);
                } else {
                    return result;
                }

            }
        }
    }
}

对算法不了解,所以求各位大神看一下有没有问题
发表于 2024-08-28 21:48:43 回复(0)
Java 已AC
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    // 物品类
    private static class good{
        public int v;  // 物品价格
        public int p;  // 重要程度
        public int q;  // 是否是附件
        public good a1 = null;
        public good a2 = null;

        public good(int v, int p, int q){
            this.v = v;
            this.p = p;
            this.q = q;
        }

        public void setAppendGoods(good a){
            if(this.a1 == null)
                this.a1 = a;
            else
                this.a2 = a;
        }

        public boolean isFollowed(){
            if(this.a1 == null && this.a2 == null)
                return false;
            else    
                return true;
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt();  // 钱数
        int n = in.nextInt();  // 购买物品数
        
        List<good> input_good = new ArrayList<>();  // 存储输入值
        List<good> input_follow_good = new ArrayList<>();
        Map<Integer,Integer> map = new HashMap<Integer,Integer>();  // 存储主件位置
        int totalCount = 0;  // 记录主件原始数组中位置
        int mainCount = 0;  // 记录主件在主件数组中位置
        while(in.hasNext()){
            int v = in.nextInt();
            int p = in.nextInt();
            int q = in.nextInt();

            if(q != 0)
                input_follow_good.add(new good(v, p, q));
            else{
                input_good.add(new good(v, p ,q));
                map.put(totalCount,mainCount);
                mainCount++;
            }
            totalCount++;
        }

        int index = 0;
        // 插入辅件
        if(!input_follow_good.isEmpty()){
            for(good g:input_follow_good){
                index = map.get(g.q-1);
                input_good.get(index).setAppendGoods(g);
            }
        }
        int len = input_good.size();

        int[][] dp = new int[m+1][len+1];
        // 边界条件 - dp[0][j] = 0 | dp[i][0] = 0
        // 辅件计算 - 0 选1 选2 两个都选
        // 状态转换方程 (不带辅件)dp[i][j] = Max(dp[i][j-1], dp[i-input[j][0]][j-1] + input[j][0] * input[j][1])  (携带辅件)dp[i][j] = Max(dp[i][j-1], dp[i-input[j][0]][j-1] + input[j][0] * input[j][1], dp[i-input[j][0]-input[j1][0]][j-1] + input[j][0] * input[j][1] +input[j1][0] * input[j1][1], ***)
        for(int i=1; i<m+1; i++){
            for(int j=1; j<len+1; j++){
                good temp = input_good.get(j-1);
                dp[i][j] = dp[i][j-1];
                if(i-temp.v >= 0){
                    dp[i][j] = Math.max(dp[i][j-1], dp[i-temp.v][j-1]+temp.v*temp.p);
                    if(temp.isFollowed()){
                        if(temp.a1 != null && i-temp.v-temp.a1.v >= 0)  // 带附件1
                            dp[i][j] = Math.max(dp[i][j],dp[i-temp.v-temp.a1.v][j-1]+temp.v*temp.p+temp.a1.v*temp.a1.p);
                        if(temp.a2 != null && i-temp.v-temp.a2.v >= 0)  // 带附件2
                            dp[i][j] = Math.max(dp[i][j],dp[i-temp.v-temp.a2.v][j-1]+temp.v*temp.p+temp.a2.v*temp.a2.p);
                        if(temp.a1 != null && temp.a2 != null && i-temp.v-temp.a1.v-temp.a2.v >= 0)  // 带附件1和2
                            dp[i][j] = Math.max(dp[i][j],dp[i-temp.v-temp.a1.v-temp.a2.v][j-1]+temp.v*temp.p+temp.a1.v*temp.a1.p+temp.a2.v*temp.a2.p);
                    }
                }
            }
        }
        System.out.println(dp[m][len]);
    }
}


发表于 2024-08-24 22:46:55 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int N = in.nextInt() / 10;
        int m = in.nextInt();
        int[][]weights = new int[m + 1][3];
        int[][]values = new int[m + 1][3];
        for (int i = 1; i < m + 1; i++) {
            int weight  = in.nextInt() / 10;
            int v = in.nextInt() * weight;
            int q =  in.nextInt();
            if (q == 0) {
                weights[i][0] = weight;
                values[i][0] = v;
            } else if (weights[q][1] == 0) {
                weights[q][1] = weight;
                values[q][1] = v;
            } else {
                weights[q][2] = weight;
                values[q][2] = v;
            }
        }
        int x = 0;
        int y = 0;
        int z1 = 0;
        int z2 = 0;
        int z  = 0;
        int max = 0;
        int[][]results = new int[m + 1][N + 1];
        for (int i = 1; i < m + 1; i++) {
            for (int j = 1; j < N + 1; j++) {
                int primary = weights[i][0];
                int secondary = weights[i][1];
                int third = weights[i][2];
                int primaryValue = values[i][0];
                int secondaryValue = values[i][1];
                int thirdValue = values[i][2];
                // 不够买
                if (primary > j) {
                    max = results[i - 1][j];
                } else if (primary + secondary > j && primary + third > j) {
                    x = results[i - 1][j];
                    y = results[i - 1][j - primary] + primaryValue;
                    max = Math.max(x, y);
                } else if (primary + secondary <= j && primary + third > j) {
                    x = results[i - 1][j];
                    y = results[i - 1][j - primary] + primaryValue;
                    // 主 + 1
                    z1 = results[i - 1][j - primary - secondary] + primaryValue +
                         secondaryValue;
                    max = Math.max(x, y);
                    max = Math.max(max, z1);
                } else if (primary + third <= j && primary + secondary > j) {
                    // 主 + 2
                    x = results[i - 1][j];
                    y = results[i - 1][j - primary] + primaryValue;
                    z2 = results[i - 1][j - primary - third] + primaryValue +
                         thirdValue;
                    max = Math.max(x, y);
                    max = Math.max(max, z2);
                } else if (primary + secondary <= j && primary + third <= j &&
                           primary + secondary + third > j) {
                    x = results[i - 1][j];
                    y = results[i - 1][j - primary] + primaryValue;
                    z1 = results[i - 1][j - primary - secondary] + primaryValue + secondaryValue;
                    z2 = results[i - 1][j - primary - third] + primaryValue + thirdValue;
                    max = Math.max(x, y);
                    max = Math.max(max, z1);
                    max = Math.max(max, z2);
                } else {
                    // 主 + 1 + 2
                    x = results[i - 1][j];
                    y = results[i - 1][j - primary] + primaryValue;
                    z1 = results[i - 1][j - primary - secondary] + primaryValue + secondaryValue;
                    z2 = results[i - 1][j - primary - third] + primaryValue + thirdValue;
                    z = results[i - 1][j - primary - secondary - third] + primaryValue +
                        secondaryValue + thirdValue;
                    max = Math.max(x, y);
                    max = Math.max(max, z1);
                    max = Math.max(max, z2);
                    max = Math.max(max, z);

                }
                results[i][j] = max;
            }
        }
        System.out.println(results[m][N] * 10);
    }
}
发表于 2024-07-07 13:39:36 回复(1)
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息 回溯算法 两组超时
public class Main {

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);

        int totalMoney = in.nextInt();

        int totalCount = in.nextInt();
        Goods[] arr = new Goods[totalCount];

        // 注意 hasNext 和 hasNextLine 的区别
        for (int i = 0; i < totalCount; i++) { // 注意 while 处理多个 case
            int v = in.nextInt();
            int p = in.nextInt();
            int q = in.nextInt();
            Goods goods = new Goods(v, p, q);
            arr[i] = goods;
        }

        for (int i = 0; i < arr.length; i++) {
            Goods goods = arr[i];
            if (goods.q != 0) {
                Goods goodsMain = arr[goods.q - 1];
                if (goodsMain.g1 == null) {
                    goodsMain.g1 = goods;
                } else {
                    // 使价格小的在前面
                    if (goodsMain.g1.v > goods.v) {
                        goodsMain.g2 = goodsMain.g1;
                        goodsMain.g1 = goods;
                    } else {
                        goodsMain.g2 = goods;

                    }

                }
            }
        }

        getMax(arr, totalMoney, 0);
        System.out.print(maxValue);
    }

    public static int maxValue = 0;

    public static int value = 0;

    public static void getMax(Goods[] arr, int totalMoney, int start) {

        if (totalMoney >= 0) {
            maxValue = Math.max(maxValue,value);
        }

        for (int i = start; i < arr.length; i++) {
       
            Goods goods = arr[i];
            // 附件跳过
            if (goods.q != 0) {
                continue;
            }
            //处理主件
            int v = goods.v;
            // 只有主件
            if (totalMoney - v >= 0) {
                value = value + goods.getVp();
                totalMoney = totalMoney - v;
                getMax(arr, totalMoney, i + 1);
                value = value - goods.getVp();
                totalMoney = totalMoney + v;
            }
            // 主件  + 附件1
            if (goods.g1 != null && totalMoney - v - goods.g1.v >= 0) {
                    value = value + goods.getVp() + goods.g1.getVp();
                    totalMoney = totalMoney - v - goods.g1.v;
                    getMax(arr, totalMoney, i + 1);
                     value = value - goods.getVp() - goods.g1.getVp();
                    totalMoney = totalMoney + v + goods.g1.v;
            }
            // 主件 + 附件2
            if (goods.g2 != null && totalMoney - v - goods.g2.v >= 0) {
                    value = value + goods.getVp() + goods.g2.getVp();
                    totalMoney = totalMoney - v - goods.g2.v;
                    getMax(arr, totalMoney, i + 1);
                     value = value - goods.getVp() - goods.g2.getVp();
                    totalMoney = totalMoney + v + goods.g2.v;
            }
            // 主件 + 附件1 + 附件2
            if (goods.g1 != null && goods.g2 != null && totalMoney - v - goods.g1.v - goods.g2.v >= 0) {
                     value = value + goods.getVp() + goods.g1.getVp() + goods.g2.getVp();
                    totalMoney = totalMoney - v - goods.g1.v - goods.g2.v;
                    getMax(arr, totalMoney, i + 1);
                     value = value - goods.getVp() - goods.g1.getVp() - goods.g2.getVp();
                    totalMoney = totalMoney + v + goods.g1.v + goods.g2.v;
               
            }
        }

    }

}

class Goods {

    public Goods(int v, int p, int q) {
        this.v = v;
        this.p = p;
        this.q = q;
    }
    // 编号
    public int number;
    // 价格
    public int v;
    // 重要程度
    public int p;
    // 所属编号
    public int q;
    // 附件1
    public Goods g1;
    // 附件2
    public Goods g2;

    public int getVp() {
        return v * p;
    }

}
发表于 2024-06-29 14:43:20 回复(0)

个人也是第一次接触算法这个领域,本身只是个搬砖的,如果解法有不好的地方,欢迎各位指出。

话不多说,我们开始。首先先贴解题的代码,使用的是面向对象的动态规划解法。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
            int limitMoney = in.nextInt();
            int n = in.nextInt();
            List<Goods> goodsList = new ArrayList<Goods>();
            for (int i = 0; i < n; i++) {
                int price = in.nextInt();
                int value = in.nextInt() * price;
                int type = in.nextInt();
                Goods goods = new Goods(i + 1, price, value, type);
                goodsList.add(goods);
            }
            ShoppingPlan shoppingPlan = calculateMaxValue(goodsList, limitMoney);
            System.out.println(shoppingPlan.getTotalValue());
        }
    }

    public static ShoppingPlan calculateMaxValue(List<Goods> goodsList,
            int limitMoney) {
        // 最大公约数
        int gcd = getArrayGcd(goodsList);
        int n = goodsList.size();
        int m = limitMoney / gcd;
        ShoppingPlan[][] dp = new ShoppingPlan[n + 1][m + 1];
        // 初始化边界
        dp[0][0] = new ShoppingPlan();
        for (int i = 1; i <= n; i++) {
            dp[i][0] = dp[0][0];
        }
        for (int j = 1; j <= m; j++) {
            dp[0][j] = dp[0][0];
        }
        // 计算动态规划矩阵
        for (int i = 1; i <= n; i++) {
            Goods goods = goodsList.get(i - 1);
            for (int j = 1; j <= m; j++) {
                // 构建新的购物方案
                ShoppingPlan plan = new ShoppingPlan();
                // 基础方案的索引值
                int planIndex = j - goods.getPrice() / gcd;
                // 是否附件
                if (goods.isAttachment()) {
                    // 索引之需大于等于0,购买的钱才是足够的
                    if (planIndex >= 0) {
                        // 获取主件
                        Goods mainGoods = goodsList.get(goods.getType() - 1);
                        // 判断选取的基础方案是否有主件,决定是否添加主件
                        boolean hasMainGoods = dp[i - 1][planIndex].hasMainGoods(goods);
                        if (!hasMainGoods) {
                            // 如果选取的基础方案没有购买主件,则需要腾出购买主件的钱,需要将基础方案再往前推
                            planIndex -= mainGoods.getPrice() / gcd;
                        }
                        // 腾出钱之后,看看够不够买,如果不够,那就不使用基础方案了,使用新方案从头开始
                        if (planIndex >= 0) {
                            // 前如果够那就复制一份基础方案
                            plan = dp[i - 1][planIndex].createSnapshot();
                        }
                        // 然后再加上买主件
                        if (!hasMainGoods) {
                            plan.addGoods(mainGoods);
                        }
                    }
                } else {
                    // 主件处理
                    if (planIndex >= 0) {
                        // 只需要判断钱够不够就行了,方案的索引大于0,就是够钱出方案,复制一份基础方案继续购买
                        plan = dp[i - 1][planIndex].createSnapshot();
                    }
                }
                // 无论主件附件都是需要加进方案判断的
                plan.addGoods(goods);
                // 看看新生成的计划有没有超过目前的钱
                if (plan.getTotalPrice() <= j * gcd) {
                    // 如果钱够,则比较上个商品使用这么多钱的方案,然后再判断哪个方案的满意度高,择优获取
                    dp[i][j] = ShoppingPlan.max(dp[i - 1][j], plan);
                    continue;
                }
                // 不够钱买新方案的,那就用上个商品在这个钱的方案
                dp[i][j] = dp[i - 1][j];
            }
        }
        // 将最终的方案返回
        return dp[n][m];
    }

    /**
     * 商品
     */
    public static class Goods {
        // 商品编号
        private int id;
        // 商品单价
        private int price;
        // 商品价值(满意度)
        private int value;
        // 商品类型(主件为0,附件大于0)
        private int type;

        public Goods(int id, int price, int value, int type) {
            this.id = id;
            this.price = price;
            this.value = value;
            this.type = type;
        }

        public int getId() {
            return this.id;
        }

        public int getPrice() {
            return this.price;
        }

        public int getValue() {
            return this.value;
        }

        public int getType() {
            return this.type;
        }

        /**
         * 商品是否附件
         * @return true/false
         */
        public boolean isAttachment() {
            return this.type > 0;
        }
    }

    /**
     * 购物方案
     */
    public static class ShoppingPlan {
        // 商品列表
        private List<Goods> goodsList;
        // 总金额
        private int totalPrice;
        // 总价值(总满意度)
        private int totalValue;

        /**
         * 构造函数,需要输入方案编号
         */
        public ShoppingPlan() {
            this.goodsList = new ArrayList<Goods>();
            this.totalPrice = 0;
            this.totalValue = 0;
        }

        private ShoppingPlan(List<Goods> goodsList, int totalPrice, int totalValue) {
            this.goodsList = goodsList;
            this.totalPrice = totalPrice;
            this.totalValue = totalValue;
        }

        /**
         * 添加商品,同时会累计总金额和总价值
         * @param goods 商品
         */
        public void addGoods(Goods goods) {
            this.goodsList.add(goods);
            this.totalPrice += goods.getPrice();
            this.totalValue += goods.getValue();
        }

        public int getTotalPrice() {
            return this.totalPrice;
        }

        public int getTotalValue() {
            return this.totalValue;
        }

        /**
         * 判断方案中是否存在当前附件的主件
         * @param attachment 附件商品
         * @return true/false
         */
        public boolean hasMainGoods(Goods attachment) {
            for (Goods mainGoods : this.goodsList) {
                if (mainGoods.getId() == attachment.getType()) {
                    return true;
                }
            }
            return false;
        }

        /**
         * 复制购物方案(不会影响到原购物方案信息)
         * @return 购物方案副本
         */
        public ShoppingPlan createSnapshot() {
            List<Goods> goodsList = new ArrayList<Goods>(this.goodsList.size());
            goodsList.addAll(this.goodsList);
            return new ShoppingPlan(goodsList, this.totalPrice, this.totalValue);
        }

        /**
         * 获取满意度高的方案
         * @param a 购物方案a
         * @param b 购物方案b
         * @return 满意度高的方案
         */
        public static ShoppingPlan max(ShoppingPlan a, ShoppingPlan b) {
            if (a.getTotalValue() >= b.getTotalValue()) {
                return a;
            }
            return b;
        }
    }

    /**
     * 用更相减损法计算公约数
     * @param a 数a
     * @param b 数b
     * @return 最大公约数
     */
    public static int gcd(int a, int b) {
        if (a < b) {
            int tmp = a;
            a = b;
            b = tmp;
        }
        return (a % b == 0) ? b : gcd(a - b, b);
    }

    /**
     * 计算数组里的所有数的最大公约数
     * @param goodsList 源数据数组
     * @return 数组里的所有数的最大公约数
     */
    public static int getArrayGcd(List<Goods> goodsList) {
        int gcd = goodsList.get(0).getPrice();
        for (int i = 1; i < goodsList.size(); i++) {
            gcd = gcd(gcd, goodsList.get(i).getPrice());
        }
        return gcd;
    }
}


这个题是背包问题的变种,基础解法是二维动态规划。不过,由于加了主件和附件的限制,需要判断的东西一下子多了很多。本人脑子不够用,就将有可能用到的西信息封装起来了,一共是两个类:ShoppingPlan(购物方案)和Goods(商品)

商品的基础属性是不会变的,通过调整购物方案里的商品列表做动态规划达到最优。

说一下动态规划二位数组的生成思路。

如果是一维的动态规划,我们可以知道它的思路是递推,也就是前面方案作为基础方案不断积累,数组的最后一个元素dp[n]就是最后的结果。一维的题,一般每一步都是一定会发生,且有规律的,只是发生的时间有交错。

沿着一维动态规划的思路拓展到二维,那就是经典的背包问题,按每件物品的选取累计,但是跟一维不同的是,物品可选可不选,这样就衍生出了分支,所以需要使用二维来记录分支。然后通过前两个物品选出来的方案作为基础,用上一个物品加入基础方案,和当前物品加入基础方案,这两个方案作比较,择优设置到当前的方案中。

背包数组的纵向是物品,横向记录了选取和不选取的值

回到商品选取,商品选取的话大致思路是按照背包问题构筑的,由于加入了主件附件联动,我们需要考虑以下问题:

1.当前的商品是否附件,如果是就需要跟主件一起计算金额

2.基础方案是否包含了主件,如果包含的话,就不能将主件再加到购物方案里面了,只能加附件

3.如果基础方案没有主件,那么我需要腾出钱去买主件,如果剩下的钱不够了,我还需要换一个基础方案,再加上主件附件,然后去比较

梳理之后,发现问题可以按以下思路解决:

1.判断商品是否附件,如果是主件,那么直接看钱够不够,然后跟上个商品在这个钱的旧方案比较就好

2.如果是附件,那么一直加钱,直到满足有一个基础方案+附件的新方案出来,如果没有,就用同价格上个商品的方案

3.判断基础方案中是否已存在主件,如果不存在主件的话,加上主件的价格,一直加钱,直到有一个基础方案+主件+附件的新方案出来,没有的话,用铜价格上个商品的方案

最后发现,同时满足钱够且满意度高才会替换方案,所以最后二维数组最后一个元素就是最优的购物方案。

由于按1块钱去构造数组和循环,会产生大量的同样的方案,且处理时间非常长,所以采用了求取商品数组的最大公约数简化数组的构成和缩短计算时间。

发表于 2024-06-23 18:29:23 回复(0)
import java.util.Objects;
import java.util.Scanner;

public class Interview {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        String[] priceAndNum = input.split(" ");
        int price = Integer.parseInt(priceAndNum[0]);
        int num = Integer.parseInt(priceAndNum[1]);
        Goods[] goodsList = new Goods[num];
        for (int i = 0; i < num; i++) {
            String goodsInfo = scanner.nextLine();
            String[] goodsArray = goodsInfo.split(" ");
            Goods goods = new Goods();
            goods.setPrice(Integer.parseInt(goodsArray[0]));
            goods.setSatisfy(Integer.parseInt(goodsArray[1]));
            goods.setAttachId(Integer.parseInt(goodsArray[2]));
            goodsList[i] = goods;
        }
        for (int i = 0; i < num; i++) {
            Goods goods = goodsList[i];
            if (goods.attachId > 0) {
                Goods main = goodsList[goods.attachId - 1];
                if (Objects.isNull(main.getFirstAttach())) {
                    main.setFirstAttach(i);
                } else {
                    main.setSecondAttach(i);
                }
            }
        }
        int [][] dp = new int[num + 1][price + 1];
        //遍历所有商品
        for (int i = 1; i <= num; i++) {
            Goods goods = goodsList[i - 1];
            //4中情况 1:主件 2:主件+附件1 3:主件+附件2 4:主件+附件1+附件2
            int mainSatisfy = goods.price * goods.satisfy;
            boolean ifAttach1 = Objects.nonNull(goods.firstAttach);
            boolean ifAttach2 = Objects.nonNull(goods.secondAttach);
            int attach1Price = ifAttach1 ? goodsList[goods.firstAttach].price : 0;
            int attach2Price = ifAttach2 ? goodsList[goods.secondAttach].price : 0;
            int attach1Satisfy = ifAttach1 ? mainSatisfy + goodsList[goods.firstAttach].satisfy * goodsList[goods.firstAttach].price : 0;
            int attach2Satisfy = ifAttach2 ? mainSatisfy + goodsList[goods.secondAttach].satisfy * goodsList[goods.secondAttach].price : 0;
            int attach1And2 = ifAttach2 && ifAttach1 ? attach1Satisfy + attach2Satisfy - mainSatisfy : 0;
            //遍历预算,动态找出满足价格范围内的最大满意度
            for (int j = 1; j <= price; j++) {
                dp[i][j] = dp[i - 1][j];
                if (goods.attachId > 0) {
                    //如果是附件,那么不放dp,dp的值为放进一件、两件、三件...商品时的最大满意度
                    continue;
                }
                if (j - goods.price >= 0) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - goods.price] + mainSatisfy);
                }
                if (ifAttach1 && (j - (goods.price + attach1Price) >= 0)) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - goods.price - attach1Price] + attach1Satisfy);
                }
                if (ifAttach2 && (j - (goods.price + attach2Price) >= 0)) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - goods.price - attach2Price] + attach2Satisfy);
                }
                if (ifAttach1 && ifAttach2 && (j - (goods.price + attach1Price + attach2Price) >= 0)) {
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - goods.price - attach1Price - attach2Price] + attach1And2);
                }
            }
        }
        System.out.println(dp[num][price]);
    }


    static class Goods {
        private Integer price;
        private Integer satisfy;
        private Integer attachId;

        private Integer firstAttach;

        private Integer secondAttach;

        public Integer getPrice() {
            return price;
        }

        public void setPrice(Integer price) {
            this.price = price;
        }

        public Integer getSatisfy() {
            return satisfy;
        }

        public void setSatisfy(Integer satisfy) {
            this.satisfy = satisfy;
        }

        public Integer getAttachId() {
            return attachId;
        }

        public void setAttachId(Integer attachId) {
            this.attachId = attachId;
        }

        public Integer getFirstAttach() {
            return firstAttach;
        }

        public void setFirstAttach(Integer firstAttach) {
            this.firstAttach = firstAttach;
        }

        public Integer getSecondAttach() {
            return secondAttach;
        }

        public void setSecondAttach(Integer secondAttach) {
            this.secondAttach = secondAttach;
        }
    }
}

发表于 2024-05-27 11:16:02 回复(0)

import java.util.*;

public class Main {

public static void main(String[] args) {

    Scanner in = new Scanner(System.in);

    int N = in.nextInt();

    int m = in.nextInt();

    int[] v = new int[m + 1]; //价格

    int[] p = new int[m + 1]; //重要度

    int[] q = new int[m + 1]; //所属主件编号

    for (int i = 1 ; i 1 ; i++) {

        v[i] = in.nextInt();

        p[i] = in.nextInt();

        q[i] = in.nextInt();

    }

    System.out.println(getMaxSat(v, p, q, N, m));

}

//获取最大满意值方法

public static int getMaxSat(int[] v, int[] p, int[] q, int N, int m) {

    Good[][] good = new Good[m + 1][3]; //g[i][j]表示i号物品的第j个附件(最多2个),i=0表示i号商品是主件,g[i][0]为空表示i号商品为附件

    int max = 0;

    int[] sat = new int [N + 1]; //sat[i]表示花费i元时的满意度

    //跟据条件初始化good对象数组

    for (int i = 1 ; i <= m ; i++) {

        Good gt = new Good(v[i], v[i] * p[i]);

        if (q[i] == 0) {

            good[i][0] = gt;

        } else { //是附件时判断是否存在另一个附件

            if (good[q[i]][1] == null)

                good[q[i]][1] = gt;

            else

                good[q[i]][2] = gt;

        }

    }

    for (int i = 1; i <= m; i++) {

        for (int j = N; j >= 0; j--) {

            Good gt0 = good[i][0];

            Good gt1 = good[i][1];

            Good gt2 = good[i][2];

            // i号商品不是主件时跳过循环

            if (gt0 == null)

                break;

            // 第i号物品为主件时列出四种情况:主,主+附1,主+附2,主+附1+附2,并记录四种情况下的最大的满意度

            else {

                //该主件没有附件

                if (gt1 == null && gt2 == null) {

                    if (gt0.v <= j) {

                        //和原来的sat[j]比较,取最大满意度并记录

                        sat[j] = Math.max(sat[j], gt0.vp + sat[j - gt0.v]);

                    }

                }

                //该主件有1个附件,若剩余金额允许购买主件和附件,比较主和主+附1的最大满意度

                if (gt1 != null) {

                    if (gt0.v <= j) {

                        sat[j] = Math.max(sat[j], gt0.vp + sat[j - gt0.v]);

                    }

                    if (gt0.v + gt1.v <= j) {

                        sat[j] = Math.max(sat[j], gt0.vp + gt1.vp + sat[j - gt0.v - gt1.v]);

                    }

                }

                //该主件有2个附件,若剩余金额允许购买主件和附件,比较主,主+附1,主+附2,主+附1+附2的最大满意度

                if (gt2 != null) {

                    if (gt0.v <= j) {

                        sat[j] = Math.max(sat[j], gt0.vp + sat[j - gt0.v]);

                    }

                    if (gt0.v + gt1.v <= j) {

                        sat[j] = Math.max(sat[j], gt0.vp + gt1.vp + sat[j - gt0.v - gt1.v]);

                    }

                    if (gt0.v + gt2.v <= j) {

                        sat[j] = Math.max(sat[j], gt0.vp + gt2.vp + sat[j - gt0.v - gt2.v]);

                    }

                    if (gt0.v + gt1.v + gt2.v <= j) {

                        sat[j] = Math.max(sat[j], gt0.vp + gt1.vp + gt2.vp + sat[j - gt0.v - gt1.v - gt2.v]);

                    }

                }

            }

        }

    }

    return sat[N];

}

}

//定义商品类

class Good {

int v;//价格

int vp;//满意度

public Good(int v, int vp) {

    this.v = v;

    this.vp = vp;

}

}

发表于 2024-05-10 14:46:06 回复(0)
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
import java.util.TreeMap;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        String[] strArray = line.split(" ");
        int totalAmt = Integer.parseInt(strArray[0]);
        int goodsCount = Integer.parseInt(strArray[1]);

        //取出所有商品
        List<Goods> goodsList = new ArrayList<Goods>();
        for (int i = 0; i < goodsCount; i++) {
            String goods = sc.nextLine();
            String[] goodsArray = goods.split(" ");
            int price = Integer.parseInt(goodsArray[0]);
            int enjoyValue = Integer.parseInt(goodsArray[1]);
            boolean isMaster = Integer.parseInt(goodsArray[2]) > 0 ? false : true;
            Goods goodsModel = new Goods(price, isMaster, enjoyValue);
            goodsList.add(goodsModel);
        }

        //用TreeMap定义排序规则
        TreeMap<String, String> treeMap = new TreeMap<String, String>
        (new Comparator<String>() {
            /**
             *  key的数据格式:满意度+"-"+序号
             *  排序规则:如果前面的key的满意度值大于后面的key的满意度值,保持顺序不变,否则就调整顺序
             */
            @Override
            public int compare(String key1, String key2) {
                String[] keyArray1 = key1.split("-");
                String[] keyArray2 = key2.split("-");
                //倒序排
                return  Integer.parseInt(keyArray2[0]) - Integer.parseInt(keyArray1[0]);
            }
        });
        calculateGoodsEnjoyResult(goodsList, totalAmt, treeMap);
        System.out.println(treeMap.get(treeMap.firstKey()));
    }
    /**
     * 计算选取商品满意度
     * 第一个参数  goodsList 商品列表 List集合模型
     * 第二个参数  totalAmt  总金额    int
     * 第三个参数  treeMap   封装结果  TreeMap模型(内部实现自定义的按key排序)
     */
    private static void calculateGoodsEnjoyResult(List<Goods> goodsList,
            int totalAmt,
            TreeMap<String, String> treeMap) {
        int  order = 0;
        for (Goods goodsModel : goodsList) {

            //单个商品价格 > 总金额,不满足购物要求
            if (goodsModel.getPrice() > totalAmt) {
                break;
            }

            //单个商品价格 <= 总金额,就计算单个商品的满意度,并添加数据到TreeMap中
            if (goodsModel.getPrice() <= totalAmt) {
                treeMap.put(goodsModel.getPrice() * goodsModel.getEnjoyValue() + "-" + order,
                            goodsModel.getPrice() * goodsModel.getEnjoyValue() + "");
                order++;
            }

            /**
             * 累算商品价格
             */
            int amtSum = goodsModel.getPrice();
            int enjoyValueSum = goodsModel.getPrice() * goodsModel.getEnjoyValue();
            boolean isBuyMaster = false;
            for (int i = goodsList.indexOf(goodsModel) + 1; i < goodsList.size(); i++) {


                //有两个商品都是主件商品,不满足购物要求
                if (goodsModel.isMaster() && goodsList.get(i).isMaster()) {
                    continue;
                }

                //之前累算已有主件商品,现在又算主件商品,也不满足购物要求
                if (isBuyMaster && goodsList.get(i).isMaster()) {
                    continue;
                }

                //累算商品价格
                amtSum +=  goodsList.get(i).getPrice();

                //累算商品价格 > 支付总额 ,不满足购物要求
                if (amtSum > totalAmt) {
                    continue;
                }

                /**
                 * 累算商品价格 <= 支付总额 ,就计算单个商品的满意度,并添加数据到TreeMap中
                 */
                enjoyValueSum += goodsList.get(i).getPrice() * goodsList.get(i).
                                 getEnjoyValue();

                treeMap.put(enjoyValueSum + "-" + order, enjoyValueSum + "");
                order++;

                if (goodsModel.isMaster() || goodsList.get(i).isMaster()) {
                    isBuyMaster = true;
                }

            }
        }


    }
    static class Goods {
        private int price;
        private boolean isMaster;
        private int enjoyValue;

        public Goods(int price, boolean isMaster, int enjoyValue) {
            this.price = price;
            this.isMaster = isMaster;
            this.enjoyValue = enjoyValue;
        }

        public int getPrice() {
            return price;
        }

        public void setPrice(int price) {
            this.price = price;
        }

        public boolean isMaster() {
            return isMaster;
        }

        public void setMaster(boolean isMaster) {
            this.isMaster = isMaster;
        }

        public int getEnjoyValue() {
            return enjoyValue;
        }

        public void setEnjoyValue(int enjoyValue) {
            this.enjoyValue = enjoyValue;
        }
    }
}



用例输入
1000 5

800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
预期输出
2200
实际输出
3500

分析:
选取
400 5 1
300 5 1

1表示是附件
支付总额:
400+300=700<1000
满意度:
400*5+300*5=3500
比答案(预期输出)中的2200要高

用例输入
50 5

20 3 5
20 3 5
10 3 0
10 2 0
10 1 0
预期输出
130
实际输出
150

分析:
选取
20 3 5
20 3 5
10 3 0

5表示有附件
0表示是主件
支付总额:
20+20+10=50 正好是50
满意度:
20*3+20*3+10*3=150
比答案(预期输出)中的130要高
发表于 2024-04-01 20:37:51 回复(1)
import java.util.ArrayList;
import java.util.List;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer line = new StringTokenizer(br.readLine());
        int money = Integer.parseInt(line.nextToken());
        int num = Integer.parseInt(line.nextToken());

        Good[] goods = new Good[num];
        int i = 0;
        while (i < num) {
            line = new StringTokenizer(br.readLine());
            int v = Integer.valueOf(line.nextToken());
            int p = Integer.valueOf(line.nextToken());
            int q = Integer.valueOf(line.nextToken());
            if (goods[i] == null) {
                goods[i] = new Good(v, p, q);
            } else {
                goods[i].v = v;
                goods[i].p = p;
                goods[i].q = q;
            }
            if (q > 0) { // 附件
                if (goods[q - 1] == null) { // 主件还未创建
                    goods[q - 1] = new Good(0, 0, 0);
                }
                if (goods[q - 1].g1 < 0) {
                    goods[q - 1].g1 = i;
                } else {
                    goods[q - 1].g2 = i;
                }
            }
            i++;
        }

        System.out.println(shopping(goods, money));
    }



    public static int shopping(Good[] goods, int money) {
        int dp[] = new int[money + 1];
        for (int i = 0; i < goods.length; i++) {
            Good g = goods[i];
            for (int j = money; j >= g.v && g.q == 0; j--) {
                // 只买主件
                dp[j] = Math.max(dp[j - g.v] + g.p * g.v, dp[j]);
                // 主 + 附1
                if (g.g1 >= 0 && j >= (g.v + goods[g.g1].v)) {
                    Good g1 = goods[g.g1];
                    dp[j] = Math.max(dp[j - g.v - g1.v] + g.p * g.v + g1.v * g1.p, dp[j]);
                }

                // 主 + 附2
                if (g.g2 >= 0 && j >= (g.v + goods[g.g2].v)) {
                    Good g2 = goods[g.g2];
                    dp[j] = Math.max(dp[j - g.v - g2.v] + g.p * g.v + g2.v * g2.p, dp[j]);
                }
                // 主 + 附1 + 附2
                if (g.g1 >= 0 && g.g2 >= 0 && j >= (g.v + goods[g.g1].v + goods[g.g2].v)) {
                    Good g1 = goods[g.g1];
                    Good g2 = goods[g.g2];
                    dp[j] = Math.max(dp[j - g.v - g1.v - g2.v] + g.p * g.v + g1.v * g1.p + g2.v *
                                     g2.p, dp[j]);
                }
            }
        }
        return dp[money];
    }


    public static class Good {
        private int v; // 价格
        private int p; // 重要性
        private int q; // 主件id
        private int g1 = -1; // 附件1
        private int g2 = -1; // 附件2

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

发表于 2024-03-25 14:01:17 回复(0)
这个算法的核心在于,他认为在循环结束时,已经求出了每一个分值下的最优解,所以当下一次循环开始的时候,会比较以下两个值来谋求最优解:假设上一次的商品a这一次的商品b
  1. 商品a在本次分数下的价值
  2. 商品b价值+ 商品a在特定分值(本次分值 - 商品b分值)下的价值
比较上述两个值,哪个值大,哪个值为当前最优解

import java.util.Scanner;


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt() / 10;
        int s = in.nextInt();

        //最大数组长度
        Good[] gs = new Good[s];

        //组装基础数据
        for (int i = 0; i < s ; i++) {
            int v = in.nextInt() / 10;
            int p = in.nextInt();
            int q = in.nextInt();
            //生成对象并按照顺序写入
            gs[i] = new Good(v, p * v, q);
        }
        //二次循环写入附件信息
        for (int i = 0; i < s ; i++) {
            Good good = gs[i];
            if (!good.isMain) {
                Good parent = gs[good.q - 1];
                if (parent.q1 == -1) {
                    parent.q1 = i;
                } else {
                    parent.q2 = i;
                }
            }
        }
        //结果集分值,物品
        int[][] res = new int[m + 1][s + 1];
        //一次循环物品
        for (int i = 1; i < s + 1 ; i++) {
            //二次循环商品价值
            for (int j = 0; j <= m ; j++) {
                Good good = gs[i - 1];
                //附件数据忽略,取上一个物品的值
                if (!good.isMain) {
                    res[j][i] = res[j][i - 1];
                } else {
                    //赋默认值,上一个物品当前分值最优解
                    res[j][i] = res[j][i - 1];
                    //主物品剩余分值优解
                    if (good.v <= j) {
                        res[j][i] = Math.max(res[j][i], good.p + res[j - good.v][i - 1]);
                    }
                    //主物品+q1+剩余分值最优解
                    if (good.q1 > -1 && good.v + gs[good.q1].v <= j) {
                        int count = good.p + gs[good.q1].p + res[j - good.v - gs[good.q1].v][i - 1];
                        res[j][i] = Math.max(res[j][i], count);
                    }
                    //主物品+q2+剩余物品最优解
                    if (good.q2 > -1 && good.v + gs[good.q2].v <= j) {
                        int count = good.p + gs[good.q2].p + res[j - good.v - gs[good.q2].v][i - 1];
                        res[j][i] = Math.max(res[j][i], count);
                    }
                    //主物品+两附件+剩余物品最优解
                    if (good.q1 > -1 && good.q2 > -1 &&
                            good.v + gs[good.q1].v + gs[good.q2].v <= j) {
                        int count = good.p + gs[good.q1].p  + gs[good.q2].p + res[j - good.v -
                                    gs[good.q1].v - gs[good.q2].v][i - 1];
                        res[j][i] = Math.max(res[j][i], count);
                    }
                }
            }
        }
        //输出结果
        System.out.println(res[m][s] * 10);
    }


    //商品对象
    static class Good {
        //商品价值
        public int v;
        //计算后的满意度
        public int p;
        //是否为附件
        public int q;
        //是否主件,默认不是
        public boolean isMain = false;
        //附件编号
        public int q1 = -1;
        public int q2 = -1;

        public Good(int v, int p, int q) {
            this.v = v;
            this.p = p;
            this.q = q;
            //提前判断好是否是主件
            if (q == 0) {
                this.isMain = true;
            }
        }
    }
}


编辑于 2024-03-14 19:51:26 回复(0)
我看过很多人写的代码,他们在“dp[i][j] = dp[i-1][j]”这里的处理都显得没有逻辑可言,下面的四个max判断大部分人第一条写的
Math.max(dp[i][j],dp[i-1][j-v] + tempdp);
,这样写逻辑根本无法自洽,同01背包问题分析,第一次如果你不买那么就是dp[i-1][j],买了就是dp[i-1][j-v] + tempdp,不存在说不买还是dp[i][j]的。 往下三条if这里之所以写dp[i][j]是因为它是同上一条计算出来的dp[i][j]的比较,是不同购买方案的比较。只要这里能理解透彻,我觉得这题大家就能懂了, 希望我下面代码对大家有所帮助。 import java.util.*; public class Main {     public static void main(String[] args) {         Scanner sc = new Scanner(System.in);         int money = sc.nextInt();         int n = sc.nextInt();         if (n <= 0 || money <= 0) System.out.println(0);         good[] Gs = new good[n + 1];         for (int i = 1; i <= n; i++) {             int v = sc.nextInt();//物品价格             int p = sc.nextInt();//物品重要度             int q = sc.nextInt();//是否主件(主件编号)             Gs[i] = new good(v, p, q);         }         for (int i = 1; i <= n; i++) {             if (Gs[i] != null && Gs[i].q > 0) { //如果是附件,则给附件ID置位,方便后面计算附件方案                 if (Gs[Gs[i].q].a1 == 0) {                     Gs[Gs[i].q].setA1(i);                 }                  else if (Gs[Gs[i].q].a2 == 0){                     Gs[Gs[i].q].setA2(i);                 }             }         }         int[][] dp = new int[n + 1][money + 1];         for (int i = 1; i <= n; i++) {             int v = 0, v1 = 0, v2 = 0, v3 = 0, tempdp = 0, tempdp1 = 0, tempdp2 = 0, tempdp3 = 0;             //只有主件             v = Gs[i].v;             tempdp = Gs[i].p * v;                //主件加附件1             if(Gs[i].a1 != 0){                    v1 = Gs[Gs[i].a1].v + v;                  tempdp1 = tempdp + Gs[Gs[i].a1].v * Gs[Gs[i].a1].p;             }               //主件加附件2             if(Gs[i].a2 != 0){                    v2 = Gs[Gs[i].a2].v + v;                 tempdp2 = tempdp + Gs[Gs[i].a2].v * Gs[Gs[i].a2].p;              }              //主件加附件1和附件2              if(Gs[i].a1 != 0 && Gs[i].a2 != 0){                  v3 = Gs[Gs[i].a1].v + Gs[Gs[i].a2].v + v;                  tempdp3 = tempdp + Gs[Gs[i].a1].v * Gs[Gs[i].a1].p + Gs[Gs[i].a2].v * Gs[Gs[i].a2].p;              }             for(int j = 1; j <= money; j++){                 if(Gs[i].q > 0) dp[i][j] = dp[i-1][j];//如果物品是附件,先不买                 else if(Gs[i].q == 0){                  dp[i][j] = j >= v? Math.max(dp[i-1][j],dp[i-1][j-v] + tempdp) : dp[i-1][j]; //Math.max(不买,买) : 钱不够                 dp[i][j] = j >= v1? Math.max(dp[i][j],dp[i-1][j-v1] + tempdp1) : dp[i][j]; //此处dp[i][j]指的是上一行的dp[i][j],即比较不同购买方案,往下的dp[i][j]的值一直是被不断刷新的                 dp[i][j] = j >= v2? Math.max(dp[i][j],dp[i-1][j-v2] + tempdp2) : dp[i][j];                  dp[i][j] = j >= v3? Math.max(dp[i][j],dp[i-1][j-v3] + tempdp3) : dp[i][j];                  }              }          }          System.out.println(dp[n][money]);      }     /** * 定义物品类 */      private static class good {          public int v; //物品的价格          public int p; //物品的重要度          public int q; //物品的主附件ID          public int a1=0; //附件1ID          public int a2=0; //附件2ID          public good(int v, int p, int q) {              this.v = v;              this.p = p;              this.q = q;          }          public void setA1(int a1) {              this.a1 = a1;          }          public void setA2(int a2) {              this.a2 = a2;          }      }  }

编辑于 2024-01-20 13:23:54 回复(0)
9/12通过,不明白问题在哪了,大佬们帮忙解读一下。
import java.util.Scanner;

public class HJ16 {

    /**
     * 【购物单】
     * <p>
     * 描述:王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的
     * 必须先买该附件所属的主件,且每件物品只能购买一次
     * 每件物品规定了一个重要度,用整数 1 ~ 5 表示
     * <p>
     * 要求:希望在花费不超过 N 元的前提下,使自己的满意度达到最大
     * <p>
     * 【解题思路】:1.创建物品属性类v-价格,p-重要度,q-主件或附件(0或主件编号)
     * 2.将输入信息放入物品类
     * 3.分四种,主件,主件+附件1,主件+附件2,主件+附件1+附件2,逐次算出满意度。
     * 4.遍历这四种情况下的最优解,合并最优解。
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // 输入
        int totalMoney = sc.nextInt();//总钱数
        int goodNumber = sc.nextInt();//物品个数
        Good[] goodArray = new Good[goodNumber + 1];
        for (int i = 1; i <= goodNumber; i++) {
            Good good = goodArray[i];
            if (good == null) {
                good = new Good();
            }
            good.setV(sc.nextInt());
            good.setP(sc.nextInt());
            good.setQ(sc.nextInt());
            if (good.getQ() > 0) {
                if (goodArray[good.getQ()] == null) {
                    goodArray[good.getQ()] = new Good();
                }
                //给主件赋值附件信息
                if (goodArray[good.getQ()].getAttach1() == null) {
                    goodArray[good.getQ()].setAttach1(good);
                } else {
                    goodArray[good.getQ()].setAttach2(good);
                }
            }
            goodArray[i] = good;

        }


        int[][] dp = new int[goodNumber + 1][totalMoney + 1];//最终的满意度
        dp[0][0] = 0;
        //每种情况的满意度数组
        int[][] level = new int[goodNumber + 1][4];
        int[][] costMoney = new int[goodNumber + 1][4];
        for (int i = 1; i <= goodNumber; i++) {

            Good g = goodArray[i];
            //只有主件
            level[i][0] = g.getV() * g.getP();
            costMoney[i][0] = g.getV();
            //附件1
            if (g.getAttach1() != null ) {
                level[i][1] = g.getV() * g.getP() + g.getAttach1().getV() * g.getAttach1().getP();
                costMoney[i][1] = g.getV() + g.getAttach1().getV();
            }
            //附件2
            if (g.getAttach2() != null) {
                level[i][2] = g.getV() * g.getP() + g.getAttach2().getV() * g.getAttach2().getP();
                costMoney[i][2] = g.getV() + g.getAttach2().getV();
            }
            //附件1+附件2
            if (g.getAttach1() != null && g.getAttach2() != null) {
                level[i][3] = g.getV() * g.getP() + g.getAttach1().getV() * g.getAttach1().getP() +
                        g.getAttach2().getV() * g.getAttach2().getP();
                costMoney[i][3] = g.getV() + g.getAttach1().getV() + g.getAttach2().getV();
            }

            for (int j = totalMoney; j >= 0; j = j - 10) {
                for (int k = 0; k < costMoney[i].length; k++) {
                    if (g.getQ() > 0) {
                        dp[i][j] = dp[i - 1][j];
                    } else {
                        if (costMoney[i][k] <= j) {
                            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - costMoney[i][k]] + level[i][k]);
                        } else {
                            dp[i][j] = dp[i - 1][j];
                        }
                    }
                }
            }
        }
        System.out.println(dp[goodNumber][totalMoney]);


    }

}

class Good {
    private int v;//价格

    private int p;//重要度

    private int q;//主件or附件

    private Good attach1;//附件1

    private Good attach2;//附件2

    public int getV() {
        return v;
    }

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

    public int getP() {
        return p;
    }

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

    public int getQ() {
        return q;
    }

    public void setQ(int q) {
        this.q = q;
    }

    public Good getAttach1() {
        return attach1;
    }

    public void setAttach1(Good attach1) {
        this.attach1 = attach1;
    }

    public Good getAttach2() {
        return attach2;
    }

    public void setAttach2(Good attach2) {
        this.attach2 = attach2;
    }
}


编辑于 2023-12-27 15:11:25 回复(1)
暴力破解,9/12通过
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

public class T16 {
    static int maxsumOfSatisfaction = 0;

    public static void main(String[] args) {
        HashMap<Integer, int[]> goods = new HashMap<>();
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        String[] split = str.split(" ");
        int money = Integer.parseInt(split[0]);
        int number = Integer.parseInt(split[1]);
        for (int i = 0; i < number; i++) {
            String temp = sc.nextLine();
            int[] detail = new int[3];
            String[] split1 = temp.split(" ");
            detail[0] = Integer.parseInt(split1[0]);
            detail[1] = Integer.parseInt(split1[1]);
            detail[2] = Integer.parseInt(split1[2]);
            goods.put(i, detail);
        }
        orderByMo(goods);
        getAllCase(0, goods, new ArrayList<>(), money, 0, 0);
        System.out.println(maxsumOfSatisfaction);


    }

    private static void orderByMo(HashMap<Integer, int[]> goods) {
        for (int i = 0; i < goods.size(); i++) {
            int[] good = goods.get(i);
            if (good[2] > i && good[2] != 0) {
                //交换主件和附件的位置
                goods.put(i, goods.get(good[2] - 1));
                goods.put(good[2] - 1, good);
                //修改附件信息
                for (int j = i + 1; j < goods.size(); j++) {
                    int[] ints = goods.get(j);
                    if (ints[2] == good[2]) {
                        ints[2] = i + 1;
                        goods.put(j, ints);
                    }
                }
            }
        }
    }

    public static void getAllCase(int index, HashMap<Integer, int[]> goods, ArrayList<Integer> tempCase, int money, int sum, int sumOfSatisfaction) {
        if (sum > money) {
            return;
        }
        ArrayList<Integer> copy = new ArrayList<>(tempCase);
        if (index == goods.size()) {
            if (tempCase.size() != 0) {
                if (sumOfSatisfaction > maxsumOfSatisfaction) {
                    maxsumOfSatisfaction = sumOfSatisfaction;
                }
            }
        } else {
            //选择购买这个商品
            int[] good = goods.get(index);
            sum += good[0];
            if (good[2] == 0) {
                tempCase.add(index);
                getAllCase(index + 1, goods, tempCase, money, sum, sumOfSatisfaction + good[0] * good[1]);
            } else {
                if (tempCase.contains(good[2] - 1)) {
                    tempCase.add(index);
                    getAllCase(index + 1, goods, tempCase, money, sum, sumOfSatisfaction + good[0] * good[1]);
                }
            }
            //选择不购买这个商品
            getAllCase(index + 1, goods, copy, money, sum - good[0], sumOfSatisfaction);
        }
    }
}


发表于 2023-12-21 01:20:53 回复(0)
暴力尝试转dp,dp逻辑直接抄写暴力尝试!通过本题!
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {

    private static class Good {
        private int id;
        private int price;
        private int value;
        private int masterId;
        private List<Good> childrenList;

        public Good(int id, int price, int value, int masterId) {
            this.id = id;
            this.price = price;
            this.value = value;
            this.masterId = masterId;
            this.childrenList = new ArrayList<>();
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int money = in.nextInt();
        int goodsCount = in.nextInt();
        Map<Integer, Good> masterMap = new HashMap<>();
        List<Good> childrenList = new ArrayList<>();
        for (int i = 0; i < goodsCount; i++) {
            Good good = new Good(i + 1, in.nextInt(), in.nextInt(), in.nextInt());
            if (good.masterId == 0) {
                masterMap.put(good.id, good);
            } else {
                childrenList.add(good);
            }
        }
        for (Good good : childrenList) {
            Good parentGood = masterMap.get(good.masterId);
            parentGood.childrenList.add(good);
        }
        Good[] goodsArray = new Good[masterMap.size()];
        int index = 0;
        for (Map.Entry<Integer, Good> entry : masterMap.entrySet()) {
            goodsArray[index++] = entry.getValue();
        }
        Map<Integer, Integer> moneyMaxValue = new HashMap<>();
//        int maxValue = processTry(goodsArray, 0, money, moneyMaxValue);
        int maxValue = processTryDp(goodsArray, 0, money);
        System.out.println(maxValue);
    }

    private static int processTry(Good[] goodsArray, int index, int money, Map<Integer, Integer> moneyMaxValue) {
        if (index >= goodsArray.length || money <= 0)
            return 0;
        Integer maxValue = moneyMaxValue.get(money);
        if (maxValue != null)
            return maxValue;
        Good curGood = goodsArray[index];
        // 要到前物品
        int masterValue = curGood.price * curGood.value;
        int masterPrice = curGood.price;
        // 只要主件
        int value1 = 0;
        int rest = money - masterPrice;
        if (rest >= 0)
            value1 = Math.max(value1, masterValue + processTry(goodsArray, index + 1, rest, moneyMaxValue));
        List<Good> childrenList = curGood.childrenList;
        // 主附件
        if (childrenList.size() >= 1) {
            Good child1 = childrenList.get(0);
            int child1Value = child1.price * child1.value;
            int child1Price = child1.price;
            // 一主一附a
            rest = money - masterPrice - child1Price;
            if (rest >= 0)
                value1 = Math.max(value1, masterValue + child1Value + processTry(goodsArray, index + 1, rest, moneyMaxValue));
            if (childrenList.size() >= 2) {
                // 一主一附b
                Good child2 = childrenList.get(1);
                int child2Value = child2.price * child2.value;
                int child2Price = child2.price;
                rest = money - masterPrice - child2Price;
                if (rest >= 0)
                    value1 = Math.max(value1, masterValue + child2Value + processTry(goodsArray, index + 1, rest, moneyMaxValue));
                // 一主两附
                rest = money - masterPrice - child1Price - child2Price;
                if (rest >= 0)
                    value1 = Math.max(value1, masterValue + child1Value + child2Value + processTry(goodsArray, index + 1, rest, moneyMaxValue));
            }
        }
        // 不要当前物品
        int value2 = processTry(goodsArray, index + 1, money, moneyMaxValue);
        maxValue = Math.max(value1, value2);
        moneyMaxValue.put(money, maxValue);
        return maxValue;
    }

    private static int processTryDp(Good[] goodsArray, int index, int money) {
        int[][] dpArray = new int[goodsArray.length + 1][money + 1];
        for (int row = dpArray.length - 2; row >= 0; row--) {
            for (int col = 1; col < dpArray[0].length; col++) {
                Good curGood = goodsArray[row];
                // 要到前物品
                int value = curGood.price * curGood.value;
                int price = curGood.price;
                List<Good> childrenList = curGood.childrenList;
                if (col - price >= 0)
                    dpArray[row][col] = value + dpArray[row + 1][col - price];
                // 主附件
                if (childrenList.size() >= 1) {
                    Good child1 = childrenList.get(0);
                    int child1Value = child1.price * child1.value;
                    int child1Price = child1.price;
                    // 一主一附a
                    if (col - price - child1Price >= 0)
                        dpArray[row][col] = Math.max(dpArray[row][col], value + child1Value + dpArray[row + 1][col - price - child1Price]);
                    if (childrenList.size() >= 2) {
                        // 一主一附b
                        Good child2 = childrenList.get(1);
                        int child2Value = child2.price * child2.value;
                        int child2Price = child2.price;
                        if (col - price - child2Price >= 0)
                            dpArray[row][col] = Math.max(dpArray[row][col], value + child2Value + dpArray[row + 1][col - price - child2Price]);
                        // 一主两附
                        if (col - price - child1Price - child2Price >= 0)
                            dpArray[row][col] = Math.max(dpArray[row][col], value + child1Value + child2Value + dpArray[row + 1][col - price - child1Price - child2Price]);
                    }
                }
                dpArray[row][col] = Math.max(dpArray[row][col], dpArray[row + 1][col]);
            }
        }
        return dpArray[0][money];
    }
}

发表于 2023-12-08 16:57:06 回复(1)
import java.util.*;

public class Main {


    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        List<LinkedList<int[]>> goods = new ArrayList<>(m);
        for (int i = 0; i < m; i++) {
            goods.add(new LinkedList<>());
        }
        for (int i = 0; i < m; i++) {
            int num1 = scanner.nextInt();
            int num2 = scanner.nextInt();
            int num3 = scanner.nextInt();
            if (num3 == 0) {
                goods.get(i).addFirst(new int[]{num1, num2});
            } else {
                goods.get(num3-1).addLast(new int[]{num1, num2});
            }
        }
        //移出空的good
        goods.removeIf(AbstractCollection::isEmpty);
        int[] dp = new int[n + 1];
        for (int i = 0; i < goods.size(); i++) {
            LinkedList<int[]> good = goods.get(i);
            for (int j = n; j >= good.get(0)[0]; j--) {
                //不管有没有附件,这步都要执行
                dp[j] = Math.max(dp[j], dp[j - good.get(0)[0]] + good.get(0)[1] * good.get(0)[0]);
                if (good.size() > 1) {
                    //选择一个附件,附件数大于1,选择一个附件这步都要执行
                    //选择一个附件有两种可能,选择附件1或者附件2,由于大于1 这里情况为选择附件1
                    if (j >= (good.get(0)[0] + good.get(1)[0])) {
                        dp[j] = Math.max(dp[j], dp[j - good.get(0)[0] - good.get(1)[0]] + good.get(0)[1] * good.get(0)[0] + good.get(1)[1] * good.get(1)[0]);
                    }

                }
                if (good.size() > 2) {
                    //同上选择一个附件有两种可能,选择附件1或者附件2,由于大于2 这里情况为选择附件2
                    if (j >= (good.get(0)[0] + good.get(2)[0])) {
                        dp[j] = Math.max(dp[j], dp[j - good.get(0)[0] - good.get(2)[0]] + good.get(0)[1] * good.get(0)[0] + good.get(2)[1] * good.get(2)[0]);
                    }
                    //选择两个附件 附件数大于2,选择两个附件这步都要执行
                    if (j >= (good.get(0)[0] + good.get(1)[0]+good.get(2)[0])) {
                        dp[j] = Math.max(dp[j], dp[j - good.get(0)[0] - good.get(1)[0] - good.get(2)[0]] + good.get(0)[1] * good.get(0)[0] + good.get(1)[1] * good.get(1)[0]+good.get(2)[1] * good.get(2)[0]);
                    }
                }
            }

        }
        System.out.println(dp[n]);

    }

}
先参考了一下评论区的思想,就是分成了不选择附件、选择一个附件、选择两个附件三种情况,独立写出😅。100%通过率
发表于 2023-09-14 20:19:12 回复(0)