/** * * @param {Object} capacity 背包容量 5 * @param {Object} weights 物品重量 [2,3,4] * @param {Object} values 物品价值 [3,4,5] * 求解该背包最多能装多少价值的物品,(每个物品不能重复,物品必须完整) */ function knapSack(capacity, weights, values){ var i,w,a,b,kS = []; //表示前i件物品恰放入一个容量为w的背包可以获得的最大价值。 //计算是从0件商品,开始的,所以增加一个商品为0,重量为0的 weights.unshift(0); values.unshift(0); var n = values.length; for( i = 0; i < n ; i++ ){ //第几件商品,从一开始 kS[i] = []; //初始化一个二维数组 for(w = 0; w <= capacity; w++){ //容量,忽略为0的容量 if( i == 0 || w == 0){ kS[i][w] = 0; }else if(weights[i] <= w){ //第i件商品的重量,如果小于当前的容量 a = values[i] + kS[i-1][w-weights[i]]; //如果加入第i件商品,则为第i件商品的价值+ 前(i-1)件商品,容量为剩余重量价值 b = kS[i-1][w]; //如果不加入第i件商品,则为前(i-1)件商品,容量为w的价值 kS[i][w] = (a > b) ? a:b; //比较两种情况的最优值 }else{ kS[i][w] = kS[i - 1][w] || 0 ; //当第i件商品容量大于当前容量时,只能选 前(i-1)件商品 } } } console.log(kS) findValues(n, capacity, kS, weights, values); return kS[n-1][capacity]; } //打印路径 function findValues(n, capacity, kS, weights, values) { var i = n-1, k = capacity; console.log('解决方案包含以下物品: '); while (i > 0 && k > 0) { if (kS[i][k] !== kS[i-1][k]) { //如果不相等,说明加入了i物品 console.log('物品' + i + ',重量: ' + weights[i] + ',价值: ' + values[i]); k = k - weights[i]; //剩余重量 } i--; //继续遍历所有物品,找到有哪些物品加入了 } } //1、当容量为商品为0或者容量为0时,可以携带的价值都为0 //2、前1件商品分别计算,容量为0-capacity的最大价值 //3、前2件商品分别计算,容量为0-capacity的最大价值 //4、..3.. //每种物品仅有一件,可以选择放或不放 //即f[i][w]表示前i件物品恰放入一个容量为w的背包可以获得的最大价值。 //则其状态转移方程便是:f[i][w]=max{f[i-1][w],f[i-1][w-weights[i]]+values[i]} (这是最根本的算法) var values = [3, 4, 5], weights = [2, 3, 4], capacity = 5; console.log(knapSack(capacity, weights, values)); //输出 7 //其实背包问题有好多版本: /* * 01背包(ZeroOnePack): 有N件物品和一个容量为V的背包。每种物品均只有一件,第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。 完全背包(CompletePack): 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 多重背包(MultiplePack): 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 * */