动态规划(0-1背包问题)

        在这个暑假过程中,又学习到了很多的算法,发现算法真的是无处不在,很神奇。下面来简单介绍一下动态规划问题。

        算法在我们生活中特别常见,例如一个小偷拿着容量为10的背包去商店偷东西,商店里有5种商品,每个商品的(重量,价值)分别为(2,6)、(2,3)、(6,5)、(5,4)、(4,6),小偷怎样才能在不超过背包容量的情况下,偷取价值总和最大的物品呢?

 

动态规划的思想:

1)最优子结构:如果一个问题的最优解中包含了子问题的最优解,就说该问题具有最优子结构。

2)重叠子问题:是指用来解原问题的递归算法可反复的解同样的子问题,而不总在产生新问题。即当一个递归算法不断地调用同一个问题时,就说该问题包含重叠子问题。 

解题步骤:

1)刻画0-1背包问题的最优解结构

2)定义最优解的值

                         0                                                  ,i=0或w=0

 C[i,w]=             C[i-1,w]                                         ,wi >w

                         max{ C[i-1,w-wi] + vi  ,  C[i-1,w] }    ,i>0且wi <=w

 

3)计算背包问题最优解的值

        // 0-1背包问题 最优解的值
        int[] w = {2, 2, 6, 5, 4}; //物品重量
        int[] v = {6, 3, 5, 4, 6}; //物品价值
        int c = 10;            //背包容量
        int[] x = new int[5];  //记录物品装入情况,0表示不装入,1表示装入
        x[0] = 1; //初始值表示第一个物品已装入背包
        int[][] m = new int[5][c + 1]; //二维表,其中m[i][j]: i个物品背包容量为j时背包的价值为m[i][j]

        // 初始化第一行,即背包中装入第一件物品                                
        for (int j = 1; j <= c; j++) {
            if (j >= w[0]) {
                //为什么要写这一段代码,不直接在下面的代码中将 for (int i = 1; i < 5; i++)中i从0开始?
                // (因为  if (j < w[i]) m[i, j] = m[i - 1, j];如果i从0开始,那么m[-1,i],就会越界

                m[0][j] = v[0];
            }
        }
        // 背包中依次装入其他的物品
        for (int i = 1; i < 5; i++) {
            for (int j = 1; j <= c; j++) {
                // 当背包容量为j时 小于 第i个物品的重量,第i个物品不能放进去
                if (j < w[i]) {
                    m[i][j] = m[i - 1][j]; //w[i]不装入背包
                } else {
                    // 将第i个物品放进容量为j的背包时,最大价值为: m[i - 1][j - w[i]] + v[i],
                    // 不将第i个物品放进容量为j的背包时,最大价值为: m[i - 1][j]
                    if (m[i - 1][j - w[i]] + v[i] > m[i - 1][j]) {
                        m[i][j] = m[i - 1][j - w[i]] + v[i]; //选择价值较大者
                    } else {
                        m[i][j] = m[i - 1][j];
                    }
                }
            }
        }
        System.out.println("背包的最大价值为:" + m[w.length - 1][c]);


 

重叠子问题:这个是在填写上面这张表格的时候可以很好的体现,例如你算C[2,2]的时候,利用公式展开C[2,2]=max { C[1,0]+6 , C[1,2] },C[1,0]与C[1,2]就不用再算一遍,直接用表格第一行算出来的结果就可以啦。

 

4)根据计算结果构造问题最优解

判断 C[i,w]   ,  C[i-1,w] 的值是否相等,若相等,则说明Xi=0,不在背包里面,否则,在里面。

特别注意的地方:编号为0的物品不能用上面的公式,计算是否在里面(会出现越界错误),利用m[0,c]=0来判断,若等于0,不在里面。

        //  显示最优解
        for (int i = 4; i >= 1; i--) {
            if (m[i][c] > m[i - 1][c]) {
                x[i] = 1; //装入背包
                c -= w[i]; //更新背包目前最大容量
            } else x[i] = 0; //没有装入背包
        }
        if (m[0][c] == 0) //判断第一个物品是否放入包中
        {
            x[0] = 0;
        } else {
            x[0] = 1;
        }

        System.out.println("物品的下标:");
        for (int i = 0; i < 5; i++) {
            if (x[i] == 1) {
                //输出最优解
                System.out.println(i);
            }
        }

        System.out.println("动态规划的表格:");

        for (int i = 0; i < w.length; i++) {
            for (int j = 0; j <= 10; j++) {
                System.out.print(m[i][j] + "   ");
            }
            System.out.println("--");
        }

    

输出结果为:

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 30
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值