王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件。
主件可以没有附件,至多有 2 个附件。附件不再有从属于自己的附件。如果要买归类为附件的物品,必须先买该附件所属的主件,且每件物品只能购买一次。
王强查到了每件物品的价格,而他只有 n 元的预算。为了先购买重要的物品,他给每件物品规定了一个重要度,用整数 1∼5 表示。他希望在花费不超过 n 元的前提下,使自己的满意度达到最大。
满意度是指所购买的每件物品的价格与重要度的乘积的之和,具体地说,记第 i 件物品的价格为 vi,重要度为 wi;现在,一共选中了 k 件物品,编号依次为 j1,j2,…,jk,则满意度计算为:
请你帮助王强计算可获得的最大的满意度。
输入描述:
第一行输入两个整数 n,m(1≦n≦32000,1≦m≦60) 代表预算、需要购买的物品总数。
此后 m 行,第 i 行输入三个整数 vi,wi,qi(1≦vi≦104; 1≦wi≦5; 0≦qi≦m) 代表第 i 件物品的价格、重要度、主件编号。特别地,qi=0 代表该物品为主件。编号即输入顺序,从 1 开始。
特别地,保证全部物品的价格 v 均为 10 的倍数。
输出描述:
在一行上输出一个整数,代表王强可获得的最大满意度。
const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;
void (async function () {
// Write your code here
let inputs = []; //保存输入内容
// 每一次有新的输入都会触发异步函数readline
while ((line = await readline())) {
inputs.push(line.split(" ").map((n) => parseInt(n)));
}
let n = 0, //声明预算
m = 0; //声明物品总数
let primary = {}, //主件价格、重要度
annex = {}; //附件价格、重要度
n = inputs[0][0];
m = inputs[0][1];
for (let i = 1; i < m + 1; i++) {
let x, y, z;
[x, y, z] = inputs[i];
if (z === 0) {
// 主件
primary[i] = [x, y];
} else {
// 附件
if (annex[z]) {
// 已经有记录,添加附件,没有记录,新增附件列表
annex[z].push([x, y]);
} else {
annex[z] = [[x, y]];
}
}
}
m = Object.keys(primary).length; //数量转为主件数量 Object.keys()方法返回一个由key组成的数组
dp = []; //生成一个m+1 * n+1的二维数组 用来存放最大满意度
// 下面遍历相当于const dp = Array.from({length:m+1},()=>Array(n+1).fill(0))
for (let i = 0; i < m + 1; i++) {
let temp = [];
for (let j = 0; j < n + 1; j++) {
temp.push(0);
}
dp.push(temp);
}
let w = [[]], //存每一个主件包括附带附件的价格
v = [[]]; //存每一个主件包括附带附件的满意度
for (let key in primary) {
let w_temp = [],//存每一次的价格
v_temp = [];//存每一次的满意度
w_temp.push(primary[key][0]); //主件价格
v_temp.push(primary[key][0] * primary[key][1]); //满意度
if (annex[key]) {
w_temp.push(w_temp[0] + annex[key][0][0]); //主件+附件1
v_temp.push(v_temp[0] + annex[key][0][0] * annex[key][0][1]);
if (annex[key].length === 2) {
//2个附件
w_temp.push(w_temp[0] + annex[key][1][0]); //主件+附件2
v_temp.push(v_temp[0] + annex[key][1][0] * annex[key][1][1]);
w_temp.push(w_temp[0] + annex[key][0][0] + annex[key][1][0]); //主件+附件1+附件2
v_temp.push(
v_temp[0] +
annex[key][0][0] * annex[key][0][1] +
annex[key][1][0] * annex[key][1][1]
);
}
}
w.push(w_temp);
v.push(v_temp);
}
//动态规划
for (let i = 1; i < m + 1; i++) {
for (let j = 10; j < n + 1; j += 10) {
//先保存上一格的满意度
let max_i = dp[i - 1][j];
//遍历主件加附件的不同情况的价格
for (let k = 0; k < w[i].length; k++) {
//满足预算
//j - w[i][k]其实就是对应的预算列
if (j - w[i][k] >= 0) {
//上一个单元格的价值 VS 当前的商品价值+剩余空间的价值
max_i = Math.max(max_i, dp[i - 1][j - w[i][k]] + v[i][k]);
}
}
dp[i][j] = max_i;
}
}
console.log(dp[m][n]);
})();