用动态规划解决背包问题

  求解背包问题:     
      给定 n 个背包,其重量分别为 w1,w2,……,wn, 价值分别为 v1,v2,……,vn    
      要放入总承重为 totalWeight 的箱子中,     
      求可放入箱子的背包价值总和的最大值。    
         
  NOTE:使用动态规划法求解 背包问题    
      设 前 n 个背包,总承重为 j 的最优值为 v[n,j], 最优解背包组成为 b[n];    
  求解最优值:    
      1. 若 j < wn, 则 : v[n,j] = v[n-1,j];    
      2. 若  j >= wn, 则:v[n,j] = max{v[n-1,j], vn + v[n-1,j-wn]}。    
  求解最优背包组成:    
      1. 若 v[n,j] > v[n-1,j] 则 背包 n 被选择放入 b[n],     
      2. 接着求解前 n-1 个背包放入 j-wn 的总承重中,     
         于是应当判断 v[n-1, j-wn] VS v[n-2,j-wn], 决定 背包 n-1 是否被选择。    
      3. 依次逆推,直至总承重为零。              
  重点: 掌握使用动态规划法求解问题的分析方法和实现思想。    
  分析方法: 问题实例 P(n) 的最优解S(n) 蕴含 问题实例 P(n-1) 的最优解S(n-1);    
             在S(n-1)的基础上构造 S(n)     
    实现思想:自底向上的迭代求解 和 基于记忆功能的自顶向下递归 。
背包建模:  
  1.     public class Knapsack {        
  2.               
  3.         /** 背包重量  */        
  4.         private int weight;        
  5.                 
  6.         /** 背包物品价值  */        
  7.         private int value;        
  8.         /***    
  9.          * 构造器    
  10.          */        
  11.         public Knapsack(int weight, int value) {        
  12.             this.value = value;        
  13.             this.weight = weight;        
  14.         }        
  15.         public int getWeight() {        
  16.             return weight;        
  17.         }        
  18.                 
  19.         public int getValue() {        
  20.             return value;        
  21.         }        
  22.                 
  23.         public String toString() {        
  24.             return "[weight: " + weight + " " + "value: " + value + "]";          
  25.         }        
  26.     }  
Java代码:
  1. public class KnapsackProblem {        
  2.                 
  3.         /** 指定背包 */        
  4.         private Knapsack[] bags;        
  5.                 
  6.         /** 总承重  */        
  7.         private int totalWeight;        
  8.                 
  9.         /** 给定背包数量  */        
  10.         private int n;        
  11.                 
  12.         /** 前 n 个背包,总承重为 totalWeight 的最优值矩阵  */        
  13.         private int[][] bestValues;        
  14.                 
  15.         /** 前 n 个背包,总承重为 totalWeight 的最优值 */        
  16.         private int bestValue;        
  17.                 
  18.         /** 前 n 个背包,总承重为 totalWeight 的最优解的物品组成 */        
  19.         private ArrayList<Knapsack> bestSolution;        
  20.                 
  21.         public KnapsackProblem(Knapsack[] bags, int totalWeight) {        
  22.             this.bags = bags;        
  23.             this.totalWeight = totalWeight;        
  24.             this.n = bags.length;        
  25.             if (bestValues == null) {        
  26.                 bestValues = new int[n+1][totalWeight+1];        
  27.             }        
  28.         }        
  29.                 
  30.         /**    
  31.          * 求解前 n 个背包、给定总承重为 totalWeight 下的背包问题    
  32.          *     
  33.          */        
  34.         public void solve() {        
  35.                     
  36.             System.out.println("给定背包:");        
  37.             for(Knapsack b: bags) {        
  38.                 System.out.println(b);        
  39.             }        
  40.             System.out.println("给定总承重: " + totalWeight);        
  41.                     
  42.             // 求解最优值        
  43.             for (int j = 0; j <= totalWeight; j++) {        
  44.                 for (int i = 0; i <= n; i++) {        
  45.                         
  46.                     if (i == 0 || j == 0) {        
  47.                         bestValues[i][j] = 0;        
  48.                     }           
  49.                     else         
  50.                     {        
  51.                         // 如果第 i 个背包重量大于总承重,则最优解存在于前 i-1 个背包中,        
  52.                         // 注意:第 i 个背包是 bags[i-1]        
  53.                         if (j < bags[i-1].getWeight()) {        
  54.                             bestValues[i][j] = bestValues[i-1][j];        
  55.                         }           
  56.                         else         
  57.                         {        
  58.                             // 如果第 i 个背包不大于总承重,则最优解要么是包含第 i 个背包的最优解,        
  59.                             // 要么是不包含第 i 个背包的最优解, 取两者最大值,这里采用了分类讨论法        
  60.                             // 第 i 个背包的重量 iweight 和价值 ivalue        
  61.                             int iweight = bags[i-1].getWeight();        
  62.                             int ivalue = bags[i-1].getValue();        
  63.                             bestValues[i][j] =         
  64.                                 Math.max(bestValues[i-1][j], ivalue + bestValues[i-1][j-iweight]);              
  65.                         } // else        
  66.                     } //else                 
  67.                } //for        
  68.             } //for        
  69.                     
  70.             // 求解背包组成        
  71.             if (bestSolution == null) {        
  72.                 bestSolution = new ArrayList<Knapsack>();        
  73.             }        
  74.             int tempWeight = totalWeight;        
  75.             for (int i=n; i >= 1; i--) {        
  76.                if (bestValues[i][tempWeight] > bestValues[i-1][tempWeight]) {        
  77.                    bestSolution.add(bags[i-1]);  // bags[i-1] 表示第 i 个背包        
  78.                    tempWeight -= bags[i-1].getWeight();        
  79.                }        
  80.                if (tempWeight == 0) { break; }        
  81.             }        
  82.             bestValue = bestValues[n][totalWeight];        
  83.         }        
  84.                 
  85.         /**    
  86.          * 获得前  n 个背包, 总承重为 totalWeight 的背包问题的最优解值    
  87.          * 调用条件: 必须先调用 solve 方法    
  88.          *     
  89.          */        
  90.         public int getBestValue() {         
  91.             return bestValue;        
  92.         }        
  93.                 
  94.         /**    
  95.          * 获得前  n 个背包, 总承重为 totalWeight 的背包问题的最优解值矩阵    
  96.          * 调用条件: 必须先调用 solve 方法    
  97.          *     
  98.          */        
  99.         public int[][] getBestValues() {        
  100.                     
  101.             return bestValues;        
  102.         }        
  103.                 
  104.         /**    
  105.          * 获得前  n 个背包, 总承重为 totalWeight 的背包问题的最优解值矩阵    
  106.          * 调用条件: 必须先调用 solve 方法    
  107.          *     
  108.          */        
  109.         public ArrayList<Knapsack> getBestSolution() {        
  110.             return bestSolution;        
  111.         }        
  112.                 
  113.     }       
  114.         
  115.     public class KnapsackTest {        
  116.               
  117.         public static void main(String[] args) {        
  118.                     
  119.             Knapsack[] bags = new Knapsack[] {        
  120.                     new Knapsack(2,13), new Knapsack(1,10),        
  121.                     new Knapsack(3,24), new Knapsack(2,15),        
  122.                     new Knapsack(4,28), new Knapsack(5,33),        
  123.                     new Knapsack(3,20), new Knapsack(18)        
  124.             };        
  125.                   
  126.             int totalWeight = 10;        
  127.             KnapsackProblem kp = new KnapsackProblem(bags, totalWeight);        
  128.                     
  129.             kp.solve();        
  130.             System.out.println(" -------- 该背包问题实例的解: --------- ");        
  131.             System.out.println("最优值:" + kp.getBestValue());         
  132.             System.out.println("最优解【选取的背包】: ");        
  133.             System.out.println(kp.getBestSolution());        
  134.             System.out.println("最优决策矩阵表:");        
  135.             int[][] bestValues = kp.getBestValues();        
  136.             for (int i=0; i < bestValues.length; i++) {        
  137.                 for (int j=0; j < bestValues[i].length; j++) {        
  138.                     System.out.printf("%-5d", bestValues[i][j]);        
  139.                 }        
  140.                 System.out.println();        
  141.             }        
  142.         }        
         
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值