背包问题

79 阅读1分钟

🍀背包问题

描述:

 # 有N件物品和一个容量是 V 的背包。每件物品只能使用一次。
 ​
 第 i 件物品的体积是 vi,价值是 wi 。
 ​
 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
 输出最大价值。
 ​
 输入格式
 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
 ​
 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
 ​
 输出格式
 输出一个整数,表示最大价值。
 ​
 数据范围
 0<N,V≤1000
 0<vi,wi≤1000

思考:

比如:

  1. 编号 1 2 3 4
  2. 体积 2 3 4 5
  3. 价值 3 4 5 6

image.png 表格a【i】【j】表示的是容量为j的背包装入前i个物品的最大价值。拿a【1】【3】和a【2】【3】举例,这里的a【2】【3】意思并不是在a【1】【3】的基础上考虑第2件物品,而应该理解为再拿一个空背包考虑前两件物品的情况。因此,如果空间不足以放入第2件,那么a【2】【3】=a【1】【3】;如果空间足够放入第2件,那么将背包容量减去第2件的容量,得j=3-3=0,而i=2-1等于1,找到a【1】【0】=0,那么物品2价值加上a【1】【0】得到总价值4,将4与a【1】【3】比较,取较大值即为a【2】【3】的值。 其他格子同理,如a【4】【8】,物品4价值6容量5,j=8-5=3,i=4-1=3,找到a【3】【3】值为4,6+4=10,10与a【3】【8】比较,10大,所以a【4】【8】=10。

image.png

实现:

 public class _02_package {
 ​
 ​
     static int[] weight = {0, 2, 3, 4, 5};
     static int[] value = {0, 3, 4, 5, 6};
     static int[][] dp = new int[5][9];
     static int[] object = new int[5];
 ​
 ​
 ​
     public static void Dynamic(){
         for (int i = 1; i < 5; i++) {
             for (int j = 1; j < 9; j++) {
                 if (weight[i] > j){
                     dp[i][j] = dp[i - 1][j];
                 }else {
                     dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
                 }
             }
         }
     }
 ​
     //   回溯去找那些放入背包了
     public static void Find(int i, int j){
         if (i == 0){     //
             for (int k = 0; k < 5; k++) {
                 System.out.println(object[k]);
             }
             return;
         }
         if (dp[i][j] == dp[i -1][j]){
             object[i] = 0;  //  未放入
             Find(i-1, j);
         }else if (dp[i][j] == (dp[i - 1][j - weight[i]] + value[i])){
             object[i] = 1;  //  已放入
             Find(i-1, j - weight[i]);
         }
     }
 ​
 ​
     public static void main(String[] args) {
 ​
         dp[0][0] = 0;
         Dynamic();
         Find(4, 8);
 ​
     }
 }