JS算法之背包问题

背包问题是一个组合优化的问题,描述如下:给一个固定大小,能够携重W的背包以及一组有价值重量的物品,找出一个最佳的方案,使得装入包中的物品重量不超过W且总价值最大。

1、问题分析

数据:物品个数n=5,物品重量weights=[2,2,6,5,4],物品价值values=[6,3,5,4,6],背包总容量W=10。

我们设置一个矩阵f来记录结果:f(i.j)可表示可选的物品为{i.....n},背包容量为j(0<j<=w) 时,背包中所放物品的最大价值;

我们先看第一行,物品0的重量为2,价值为6,当容量为0时,什么也放不下,因此第一个格子只能填0,程序表示f(0,0)=0;当j=1时,依然放不下物品0,所以依旧为0,即f(0,1)=0;当j=2时,能放下物品0,则表示为f(0,2)=6,当j=3时,依旧能放下,则表示为f(0,3)=6,依次内推可得第一行的结果:

根据第一行,可以得到以下方程:

f(i,j)=\left \{ 0,j<w(i) ;\right v(i),j>=w(i) \}

重量价值物品id012345678910

2

60

0

0

6

6

6

6

6

6

6

6

6

231

0

0

6

6

9

9

9

9

9

9

9

652

0

0

6

6

9

9

9

9

11

11

14

543

0

0

6

6

9

9

9

10

11

13

14

464

0

0

6

6

9

9

12

12

15

15

15

再看第二行,当j=0时,依旧什么都放不下,第一个格子填0,当j=1时,依旧如此,当j=2时,可以选择放不放如物品1:

如果不放入物品1,则背包中有物品0,最大价值为6,即f(0,j)

如果放入物品1,要算出背包放入1后还有多少的容量,然后再根据容量查出他的价值,再加上物品1的价值,即表示为

f(0,j-w(1))+v(1),放与不放要通过比较来决定:

f(1,j)=max\left \{ f(0,j),f(0,j-w(1))+v(1) \right \} 

显然此处填6,当j=3时,情况相同,当j=4时,能同时放下,f(1,4)=9,当j>4时,背包只能放入物品0和1,所以最大价值为9;

再看第三行,当j=0、1,什么都放不下,当j=2时,虽然放不下物品2,但是表中可看出,背包的最大容量为6,当j=8时,背包可以放物品0、1,也可以物品0、2,和1、2,物品0、1的价值,可以看到为9,最优值为0/2,总价值为11,当j=10时,三个物品能装下,总价值为14;

整理方程可得到第1行和第2行的使用方程:

f(i,j)=\left \{ f(i-1,j) j<w(i)\bigcap i>0;max\left \{f(i-1,j), f(i-1,j-w(i))+v(i) j>=w(i)\right \}\right \}

根据方程,计算各列得出结果,根还有0-1背包问题的最优方案,得到方程式:

代码如下:

function knapsack(weights, values, w){
    var n = weights.length -1;//获取物品个数
    var f=[[]];//定义f的矩阵
    for(var j=0;j<=w;j++){
        if(j<weights[0]){//容量当不下物品0的重量,价值为0
        f[0][j]=0;
        }else{
            f[0][j]=values[0];//否则容量为物品0的价值
            }
        }
    for(var j=0;j<=w;j++){
        for(var i=1;i<=n;i++){
            if(!f[i]){//创建新的一行
                f[i]=[];
            }
            if(j<weights[i]){//等于之前的最优值
                f[i][j]=f[i-1][j];
            }else{
                f[i][j]=Math.max(f[i-1][j],f[i-1][j-weights[i]]+values[i]);
                }
            }
        }
    return f[n][w];
}

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页