Java实现0-1背包问题

给定n种物品和一个背包。物品i的重量是w^{i},其价值为b^{i} ,背包的容量为W。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大? (w^{i} , b^{i}W 都是整数)

                                              

定义子问题

将物品用 1,2,... ,n编号, 子问题可以定义为 S_{k} = {在1, 2, ... , k号物品中找最优解}

问题是: 我们能否将问题(S_{n} )的最优解 用子问题 (S_{k})的最优解表示?

                                           

定义新的子问题

1.增加一个参数 w : S_{k}中的物品的重量

2.定义 B[w][k] =放入背包中的编号不超过k重量不超过w的物品的总价值.

                                       

附java代码

package package0_1;

/**

 *  0-1背包问题

 * @author Dudu

 * @date 2018-11-11

 */

public class Knapsack0_1Algorithm {

   public static void marknumber(int n,int W,int[][] B ,int[] b,int v)

   {

      //给选择到的物品打标号1 表示选择 ,0表示不选

      int[] x = new int[n];

      while (v > 0) {

        flag:for (int i = 1;i <= n;i++) {

           for (int w = 1;w <= W;w++) {

              if (B[w][i] == v) {

                 //按列选择第一个达到最优值的位置得到第一个编号,减去当前编号的价值,得到上一个物品的价值,再去搜索上一个物品的编号

                 x[i-1] = 1;

                 v = v - b[i-1];

                 break flag;

              }

           }

        }

      }

      System.out.print("选择装入背包的物品编号为:"); //从1开始编号

      for (int j = 0;j < n;j++) {

        if (x[j] == 1) {

           System.out.print(j+1+" ");

        }    

      }

      System.out.println();   

   }

   public static int knapsack0_1(int n,int[] b,int[] wlist,int W) {

      /**

       * n: 物体总数

       * b: 价值数组 存放每个物品的价值

       * wlist: 重量数组 存放每个物品的重量

       * W: 背包所能够承载的总重量

       */

      int[][] B = new int[W+1][n+1];

      for (int w = 0;w <=W;w++) {

        B[w][0] = 0;

      }

      for (int i = 1;i <= n;i++) {

        B[0][i] = 0;

        for (int w = 1;w <= W;w++) {

           try {        

              if (wlist[i-1] <= w) {

                 B[w][i] = Math.max(b[i-1] + B[w-wlist[i-1]][i-1], B[w][i-1]);

//               if (b[i-1] + B[w-wlist[i-1]][i-1] > B[w][i-1])

//               {

//                  B[w][i] = b[i-1] + B[w - wlist[i-1]][i-1];

//               }

//               else {

//                  B[w][i] = B[w][i-1];

//               }

              }

              else

              {

                 B[w][i] = B[w][i-1];

              }

           }catch(IndexOutOfBoundsException e){

              System.out.println("IndexOutOfBoundsException");

              continue;

           }

        }

      }

      System.out.println("输出B矩阵如下:行代表W,列代表物品编号n");

      for (int w = 0;w <= W;w++) {

        for (int i = 0;i <= n;i++) {

           System.out.print(B[w][i]+"\t");

        }    

        System.out.println();

      }

      marknumber(n,W,B,b,B[W][n]);

      return B[W][n]; 

   }

   public static void main(String[] args) {

      // TODO Auto-generated method stub

      int[] w = {2,3,4,5,9};

      int[] b = {3,4,5,8,10};

      int n = w.length;

      int W = 20;

      int value = knapsack0_1(n,b,w,W);

      System.out.println("价值为:"+value);

   }

}

 

输出结果

输出B矩阵如下:行代表W,列代表物品编号n

0  0  0  0  0  0 

0  0  0  0  0  0 

0  3  3  3  3  3 

0  3  4  4  4  4 

0  3  4  5  5  5 

0  3  7  7  8  8 

0  3  7  8  8  8 

0  3  7  9  11 11

0  3  7  9  12 12

0  3  7  12 13 13

0  3  7  12 15 15

0  3  7  12 16 16

0  3  7  12 17 17

0  3  7  12 17 17

0  3  7  12 20 20

0  3  7  12 20 20

0  3  7  12 20 21

0  3  7  12 20 22

0  3  7  12 20 23

0  3  7  12 20 25

0  3  7  12 20 26

选择装入背包的物品编号为:1 3 4 5

价值为:26

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值