0-1背包问题

什么是0-1背包问题?

对于一种物品,要么装入背包,要么不装。所以对于一种物品的装入状态可以取0和1.我们设物品i的装入状态为xi,xi∈ (0,1),此问题称为0-1背包问题。

问题描述:

   给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装
入背包中物品的总价值最大?

思路:

根据动态规划解题步骤(问题抽象化、建立模型、寻找约束条件、判断是否满足最优性原理、找大问题与小问题的递推关系式、填表、寻找解组成)找出01背包问题的最优解以及解组成,然后编写代码实现。

动态规划求解背包问题

  1 package com.lzp.util.dynamic;
  2 
  3 /**
  4  * @Author LZP
  5  * @Date 2021/3/21 10:50
  6  * @Version 1.0
  7  *
  8  * 0-1背包问题
  9  */
 10 public class Knapsack {
 11 
 12     /**
 13      * 物品重量
 14      */
 15     private static int[] w = {3, 2, 1};
 16 
 17     /**
 18      * 物品价值
 19      */
 20     private static int[] v = {2000, 1500, 800};
 21 
 22     /**
 23      * val[i][j] = k 代表前i个物品装入重量为j的背包中最大价值为k
 24      */
 25     private static int[][] val = new int[4][5];
 26 
 27     private static int[][] choice = new int[4][5];
 28 
 29     public static void main(String[] args) {
 30         // 1、初始化val数组,不过Java中默认的int类型数组的值是0,所以不需要,但是这里为了步骤逻辑就写一下
 31         for (int i = 0; i < val.length; i++) {
 32             val[i][0] = 0;
 33         }
 34         for (int i = 0; i < val[0].length; i++) {
 35             val[0][i] = 0;
 36         }
 37 
 38 //        for (int i = 0; i < val.length; i++) {
 39 //            for (int j = 0; j < val[i].length; j++) {
 40 //                System.out.printf("%d ", val[i][j]);
 41 //            }
 42 //            System.out.println();
 43 //        }
 44 
 45         // 2、利用公式给val数组赋值,这里从1个物品和背包重量为1开始考虑
 46         /*
 47             公式:
 48                 当w[i] > j时,val[i][j] = val[i - 1][j]
 49                 当j >= w[i]时,val[i][j] = max{val[i - 1][j], v[i] + val[i - 1][j - w[i]]}
 50          */
 51         for (int i = 1; i < val.length; i++) {
 52             for (int j = 1; j < val[i].length; j++) {
 53                 // 由于程序里面,数组中的下标是从0开始,所以这里我们获取第1个物品的重量时,要-1
 54                 if (w[i - 1] > j) {
 55                     /*
 56                          第i件物品的重量比此时背包的最大重量还大,所以放不进去,只能将前i - 1个物品放入背包重
 57                          量为j是的最大价值赋值给此时前i个物品放入背包重量为j,作为此时的最大价值
 58                      */
 59                     val[i][j] = val[i - 1][j];
 60                 } else {
 61                     /*
 62                         进入else,表示此时第i件物品的重量不超过此时背包的重量,即可以尝试放入,然后将最后产生的最大价值
 63                         于之前产生的最大价值相比较,选出最大作为此时的最大价值
 64 
 65                         注意:这里如果想要在最终的结果获取到底选了哪些物品放入背包中,就需要用一个二维数组去保存记录每次
 66                         最优的选择
 67                      */
 68                     // 此时这里就不能直接取val[i][j] = max{val[i - 1][j], v[i] + val[i - 1][j - w[i]]}的最大值了
 69                     // 需要利用if-else判断
 70                     if (val[i - 1][j] < v[i - 1] + val[i - 1][j - w[i - 1]]) {
 71                         // 如果最优就用1,标志,默认为0
 72                         choice[i][j] = 1;
 73                         val[i][j] = v[i - 1] + val[i - 1][j - w[i - 1]];
 74                     } else {
 75                         val[i][j] = val[i - 1][j];
 76                     }
 77                 }
 78             }
 79         }
 80 
 81         for (int i = 0; i < val.length; i++) {
 82             for (int j = 0; j < val[i].length; j++) {
 83                 System.out.printf("%4d\t", val[i][j]);
 84             }
 85             System.out.println();
 86         }
 87 
 88         // 打印选的物品,发现这样会打印出来很多冗余数据
 89         /*
 90             选了第1件物品
 91             选了第1件物品
 92             选了第2件物品
 93             选了第3件物品
 94             选了第3件物品
 95             选了第3件物品
 96          */
 97 //        for (int i = 0; i < choice.length; i++) {
 98 //            for (int j = 0; j < choice[i].length; j++) {
 99 //                if (choice[i][j] == 1) {
100 //                    System.out.printf("选了第%d件物品\n", i);
101 //                }
102 //            }
103 //        }
104 
105         // 改进:中间产生的最优不需要,所以直接返过来,从后往前输出即可
106         int row = choice.length - 1;
107         int col = choice[0].length - 1;
108         while (row > 0 && col > 0) {
109             if (choice[row][col] == 1) {
110                 System.out.printf("选了第%d件物品\n", row);
111                 // 减去当前放入的第row件物品,让其去找前i - 1件物品装入col - w[row - 1]时的最大价值
112                 col -= w[row - 1];
113             }
114             // 直接去找前row - 1件物品装入col时的最大价值
115             row--;
116         }
117     }
118 }

运行结果:

 

posted @ 2021-03-21 13:11  没有你哪有我  阅读(122)  评论(3编辑  收藏  举报