经典算法题04-动态规划算法(背包问题)

本来我是想解决公共最长子序列问题,但是在解题过程中需要先清楚动态规划算法,故先用动态规划算法中最经典的背包问题来说明。

背包问题

问题描述

有N件物品和一个容量为V的背包,第i件物品的费用是c[i],价值是w[i],求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大?

实际生活中的例子可以描述为小偷拿个袋子去偷东西,拿下图中的哪些东西装满背包才能获取最大价值?

这个问题的特点是:每种物品只有一件,可以选择放或者不放。
这里写图片描述
我们把题目具体下:

有3个商品,背包的体积为10,他们的体积为c[]={3,4,5}; 价值为 w={4,5,6}。V=10,N=3,c[]={3,4,5}, w={4,5,6}

从转移方程上可以看出,前i个物品的最优解只依赖于前i-1个物品最优解,而与前i-2,i-3,…各物品最优无直接关系,可以利用这个特点优化存储空间,即只申请一个一维数组即可,算法时间复杂度(O(VN))为:

for i=1..N

  for v=V..0

    f[v]=max{f[v],f[v-c[i]]+w[i]};

注意v的遍历顺序!!!
下面几种背包用到类似优化,以后不再赘述。

分析

在求最优解的背包问题中,一般有两种不同的问法:1、要求“恰好装满背包”时的最优解;2、求小于等于背包容量的最优解,即不一定恰好装满背包。

这两种问法,在初始化的时候是不同的。
(1)背包不一定装满

这里写图片描述
(2)背包一定装满
注意初始值,其中-inf表示负无穷:
这里写图片描述
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。可以将背包问题的求解看作是进行一系列的决策过程,即决定哪些物品应该放入背包,哪些不放入背包。

如果一个问题的最优解包含了物品n,即Xn = 1,那么其余X1, X2, …..,Xn-1
一定构成子问题1,2,…..,n-1在容量C - cn时的最优解。如果这个最优解不包含物品n,即Xn = 0;
那么其余 X1, X2…..Xn-1一定构成了子问题 1,2,….n-1在容量C时的最优解。 //请各位仔细品味这几句话

根据以上分析最优解的结构递归定义问题的最优解: f[i][v] = max{ f[i-1][v] , f[i-1][v - c[i]] + v[i]}

编码

import java.io.IOException;

/**
 * @param
 * @Title: 动态规划-背包问题
 * @Author: xuming
 * @Description:
 * @date:2016/5/31 9:22
 * @return
 */
public class myMathDemo2 {

    public static void main(String[] args) throws IOException {

        int c[] = {0, 3, 4, 5};
        int v[] = {0, 4, 5, 6};
        int f[][] = new int[4][11];

        for (int i = 1; i < 4; i++)
            for (int j = 1; j < 11; j++) {
                if (c[i] > j)//如果背包的容量,放不下c[i],则不选c[i]
                    f[i][j] = f[i - 1][j];
                else {
                    f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - c[i]] + v[i]);//转移方程式
                    System.out.println(f[i][j]);
                }
            }
        System.out.println("last answer: " + f[3][10]);
        for (int m = 0; m < 4; m++) {
            for (int n = 0; n < 11; n++) {
                System.out.println("the matrix answer f[" + m + "][" + n + "]:" + f[m][n]);
            }
        }


    }


}

结果是:
这里写图片描述

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值