题解 | #购物单#
购物单
https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4
import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static int[][] dpFlag; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt() / 10; // 总钱数 N<3200 int m = sc.nextInt(); // 可购买的物品的个数 m <60 Map<Integer, List<Integer>> data1 = new HashMap<>(); // 0:价格 1:重要度(1-5) 2:主件还是附件 Map<Integer, List<Integer>> data2 = new HashMap<>(); // 0:价格 1:重要度(1-5) 2:主件还是附件 for (int i = 0; i < m; i++) { List<Integer> tmp = new ArrayList<>(); for (int j = 0; j < 3; j++) { if(j == 0){ tmp.add(sc.nextInt() / 10); // 价格都是10的倍数,故除10,减少dpFlag存储空间 } else { tmp.add(sc.nextInt()); } } if (tmp.get(2) == 0) { data1.put(i + 1, tmp); } else { data2.put(i + 1, tmp); } } int ret = gwd(data1, data2, N, m); System.out.println(ret * 10); // 结果要乘10 } private static int gwd(Map<Integer, List<Integer>> data1, Map<Integer, List<Integer>> data2, int N, int m) { // 处理数据,主商品放入data1,存在附件,则通过value的的list查找,如果list.size == 3,表示没有附件,list.size == 4,有1个附件,list.size == 5,有2个附件,data2存储附件信息,通过list列表数据进行查找 for (Integer key : data2.keySet()) { int q = data2.get(key).get(2); data1.get(q).add(key); } Set<Integer> tmp = new HashSet<>(); for (Integer key : data1.keySet()) { tmp.add(key); } for (Integer key1 : tmp) { data1.put(key1 + 60, data1.get(key1)); data1.remove(key1); } int index = 1; tmp.clear(); for (Integer key : data1.keySet()) { tmp.add(key); } for (Integer key1 : tmp) { data1.put(index++, data1.get(key1)); data1.remove(key1); } dpFlag = new int[N + 1][data1.size() + 1]; for (int i = 0; i <= N; i++) { for (int j = 0; j <= data1.size(); j++) { dpFlag[i][j] = -1; } } return dp(data1, data2, N, data1.size()); } private static int dp(Map<Integer, List<Integer>> data1, Map<Integer, List<Integer>> data2, int N, int m) { if (m == 0) { return 0; } else if (N == 0) { return 0; } if (dpFlag[N][m] != -1) { // 查找记录,找到记录不再计算 return dpFlag[N][m]; } List<Integer> zhu = data1.get(m); int v1 = 0, v2 = 0, v3 = 0, w1 = 0, w2 = 0, w3 = 0; // 商品价格和重要度 int b0 = 0, b1 = 0, b21 = 0, b22 = 0, b3 = 0; // 购买0个商品的最大满意度,只买1个主商品,买主商品和附件1,买主商品和附件2,买主商品和附件1、附件2 int ret = 0; // 记录计算数据 b0 = dp(data1, data2, N, m - 1); // b0计算是任意条件需要的,提到最外处 if (zhu.size() == 3) { // 该主商品没有附件 v1 = zhu.get(0); w1 = zhu.get(1); if (N >= v1) { // 买的起主商品 b1 = dp(data1, data2, N - v1, m - 1) + v1 * w1; ret = Math.max(b0, b1); dpFlag[N][m] = ret; return ret; } else { // 买不起 dpFlag[N][m] = b0; return b0; } } else if (zhu.size() == 4) { // 该主商品有1个附件 v1 = zhu.get(0); w1 = zhu.get(1); v2 = data2.get(zhu.get(3)).get(0); w2 = data2.get(zhu.get(3)).get(1); if (N >= v1) { // 分支判断,减少b1重复计算 b1 = dp(data1, data2, N - v1, m - 1) + v1 * w1; } if (N >= v1 + v2) { // 买的起主商品1和唯一附件 b21 = dp(data1, data2, N - v1 - v2, m - 1) + v1 * w1 + v2 * w2; ret = Math.max(Math.max(b0, b1), b21); dpFlag[N][m] = ret; return ret; } else if (N >= v1) { // 只买的起主商品1 ret = Math.max(b0, b1); dpFlag[N][m] = ret; return ret; } else { // 买不起商品 dpFlag[N][m] = b0; return b0; } } else { v1 = zhu.get(0); w1 = zhu.get(1); v2 = data2.get(zhu.get(3)).get(0); w2 = data2.get(zhu.get(3)).get(1); v3 = data2.get(zhu.get(4)).get(0); w3 = data2.get(zhu.get(4)).get(1); if (N >= v1) { // 计算b1 b1 = dp(data1, data2, N - v1, m - 1) + v1 * w1; } if (N >= v1 + v2) { // 计算b21,即购买主商品和附件1的最大满意度 b21 = dp(data1, data2, N - v1 - v2, m - 1) + v1 * w1 + v2 * w2; } if (N >= v1 + v3) { // 计算b22,即购买主商品和附件2的最大满意度 b22 = dp(data1, data2, N - v1 - v3, m - 1) + v1 * w1 + v3 * w3; } if (N >= v1 + v2 + v3) { // 买的起主商品和附件1、附件2 b3 = dp(data1, data2, N - v1 - v2 - v3, m - 1) + v1 * w1 + v2 * w2 + v3 * w3; // 计算b3,即购买主商品和附件1和附件2的最大满意度 ret = Math.max(Math.max(Math.max(b0, b1), Math.max(b21, b22)), b3); dpFlag[N][m] = ret; return ret; } else if (N >= v1 + v2 || N >= v1 + v3) { // 买的起主商品以及(附件1或附件2) ret = Math.max(Math.max(b0, b1), Math.max(b21, b22)); dpFlag[N][m] = ret; return ret; } else if (N >= v1) { // 只买的起附件1 ret = Math.max(b0, b1); dpFlag[N][m] = ret; return ret; } else { // 都买不起 dpFlag[N][m] = b0; return b0; } } } }#递归##动态规划求购物单问题##记录子问题解#