动态规划--01背包问题(2)

   根据前面的分析,我们已经画出了一个表格,表格的最后一个格子是背包的最大价值,在展示代码实现前,我还是想先说一下写代码前的思路,毕竟,有了思路才能行文如流水。没错,下面要说动态规划的步骤。

 

        1. 刻画背包问题的最优解的结构:

  如果一个问题的最优解包含了物品n,那么其余n-1个物品一定构成了子问题在容量为W-Wn时的最优解;如果这个问题的最优解不包含物品n,那么其余n-1个物品一定构成了子问题在容量为W时的最优解。

 

       2. 递归定义最优解的值

       F(n,W) =0    (n=0或W=0);

       F(n,W)=F(n-1,W)   (W<Wn);

       F(n,W) = max(F(n-1,W),F(n-1,W-Wn) + Vn)  (n>0且Wn<=W)

 

      3. 计算背包问题最优解的值(终于可以看代码了)

 

 

/**
 * 01背包问题:有一个背包可盛的重量为4,现有3个物品,重量和价值如下表,问:如何让包内装入的物品具有最大的总价值?
 * Created by gu.haiyan on 2017/7/10.
 */
public class DynamicProgramming_01bag {

    //动态规划法求解
    public static int getMostValueByDP(int n, int w, int[] values, int[] weights){

        int[] preResults = new int[w+1];
        int[] results = new int[w+1];

        //填充表格第一行,也就是只有一个物品的情况
        for (int i = 1; i <= w; i++) {
            if (i < weights[0]){
                preResults[i] = 0;
            }else {
                preResults[i] = values[0];
            }
            System.out.print(" " + preResults[i]);
        }
        System.out.println("");

        //填充表格剩余行数
        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= w; j++) {
                if (j < weights[i]){
                    results[j] = preResults[j];
                    System.out.print(" " + results[j]);
                }else {
                    results[j] = Math.max(preResults[j],preResults[j-weights[i]] + values[i]);
                    System.out.print(" " + results[j]);
                }
            }
            preResults = results.clone();
            System.out.println("");
        }
        return results[w];
    }
    
    public static void main(String[] args) {
        int[] g = {1500,3000,2000};
        int[] p = {1,4,3};
        int gold = getMostValueByDP(3,4,g,p);
        System.out.println("最大价值是 " +gold);
    }
}

 

  运行结果:

 

  

 

        到这里我们已经求得了背包的最大价值。但,我们究竟在包里放入了哪几个物品该怎么算呢?  小编嘱咐:  一定要自己把那个递归的定义式写一写,确保自己明白了哦。


2018年11月7日14:33:36更新:

 

使用二维数组保存物品价值,并打印出最终背包里放入了哪些物品,1代表放入,0代表没有。

/**
     * 使用二维数组实现,并打印最优解的构成
     * @param n 物品个数
     * @param w 背包容量
     * @param values 每个物品的价值
     * @param weights 每个物品的重量
     */
    public static void getMostValueByDP1(int n, int w, int[] values, int[] weights){
        int[][] v = new int[n+1][w+1];
        for (int i =0;i<=n;i++){//第0行和第0列初始化为0,方便后续第一个物品计算时取前面一行的值
            v[i][0] = 0;
        }
        for (int j =0;j<=w;j++){
            v[0][j] =0;
        }
        for (int i =1;i<=n;i++){//真正开始填充表格,计算每个格子的最大价值
            for (int j =1;j<=w;j++){
                if (weights[i-1]>j){
                    v[i][j] = v[i-1][j];
                }else {
                    v[i][j] = Math.max(values[i-1] + v[i-1][j-weights[i-1]],v[i-1][j]);
                }
                System.out.print(v[i][j]+" ");
            }
            System.out.println();
        }
        int[] exists = new int[n];//打印最优解构成,倒着计算,如果v[i][w] > v[i-1][w],说明第i个物品在背包中。
        for (int i =n;i>0;i--){
            if(v[i][w] > v[i-1][w]){
                exists[i-1] = 1;
                w = w - weights[i-1];
            }else {
                exists[i-1] = 0;
            }
            System.out.print(exists[i-1] + ",");
        }
    }

    public static void main(String[] args) {
        int[] values = {1000, 2000, 3000, 4000, 1500, 5000, 200, 400};
        int[] weights = {1, 3, 4, 2, 5, 4, 5, 1};
        getMostValueByDP1(values.length,4,values,weights);
    }

 

运行结果:

            

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值