题解 | #购物单#
购物单
https://www.nowcoder.com/practice/f9c6f980eeec43ef85be20755ddbeaf4
/*/ 一、思路:1、常规动态规划; 2、将子物品另外存放,不单独dp遍历,在dp遍历到父物品时,将所有子物品在一同父物品遍历。 二、其中有两个子物品的父物品遍历思路如下: ①只购买一个父物品; ②父物品和某一个子物品; ③父物品和另一个子物品; ④父物品和两个子物品; ⑤最后将所有情况比较大小即可。 三、因情况过多,代码可能过长。因此,可以考虑在dp循环中使用continue,更适合本题实际情况,来减少代码复杂度。 /*/ import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int all = in.nextInt(), n = in.nextInt(); int w[] = new int[n], v[] = new int[n], st[] = new int[n];//存储价格、重要度、是否是子物品; ArrayList<Integer> list[] = new ArrayList[n];//存储子物品; int ans[] = new int[all + 1];//一维滚动数组存储答案; for(int sa = 0; sa < n; sa ++) list[sa] = new ArrayList<Integer>();//初始化; for(int sa = 0; sa < n; sa ++){ w[sa] = in.nextInt(); v[sa] = in.nextInt(); int tim = in.nextInt(); st[sa] = tim; if(tim == 0) continue; list[tim - 1].add(sa); }//记忆数据; for(int sa = 0; sa < n; sa ++){//双重for循环dp; for(int wq = all; wq >= 0; wq --){ if(w[sa] > wq || st[sa] != 0) continue;//筛选掉子物品和超重物品; ans[wq] = Math.max(ans[wq], ans[wq - w[sa]] + v[sa] * w[sa]); if(list[sa].size() == 0) continue;//筛选掉没有子物品的父物品; int ind = list[sa].get(0); if(w[sa] + w[ind] <= wq)//筛选掉超重物品,此时不能用continue,防止跳走导致少遍历一种情况 ans[wq] = Math.max(ans[wq], ans[wq - w[sa] - w[ind]] + v[sa] * w[sa] + v[ind] * w[ind]); if(list[sa].size() == 1) continue;//筛选掉只有一个子物品的父物品; int ind2 = list[sa].get(1); if(w[sa] + w[ind2] > wq) continue;//继续添加限制条件,筛选掉超重的物品; ans[wq] = Math.max(ans[wq], ans[wq - w[sa] - w[ind2]] + v[sa] * w[sa] + v[ind2] * w[ind2]); if(w[sa] + w[ind2] + w[ind] > wq) continue;//继续筛选掉超重物品; ans[wq] = Math.max(ans[wq], ans[wq - w[sa] - w[ind] - w[ind2]] + v[sa] * w[sa] + v[ind2] * w[ind2] + v[ind] * w[ind]); } } System.out.println(ans[all]);//输出答案。 } }