0/1背包问题的动态规划法求解 —— Java 实现
来源:互联网 发布:开淘宝描述店铺怎么写 编辑:程序博客网 时间:2024/05/19 21:41
0/1背包问题的动态规划法求解,前人之述备矣,这里所做的工作,不过是自己根据理解实现了一遍,主要目的还是锻炼思维和编程能力,同时,也是为了增进对动态规划法机制的理解和掌握。
值得提及的一个问题是,在用 JAVA 实现时, 是按算法模型建模,还是用对象模型建模呢? 如果用算法模型,那么 背包的值、重量就直接存入二个数组里;如果用对象模型,则要对背包以及背包问题进行对象建模。思来想去,还是采用了对象模型,尽管心里感觉算法模型似乎更好一些。有时确实就是这样,对象模型虽然现在很主流,但也不是万能的,采用其它的模型和视角,或许可以得到更好的解法。
首先是问题描述:给定n种物品和一背包,物品i的重量是wi,其价值是pi,背包的容量是M,问如何选择装入背包中的物品总价值最大
下面是思路的基本过程
问题的特点是:每种物品一件,可以选择放1或不放0。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
方程的含义:“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”,价值为f[i-1][v];如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。
背包建模:
- package algorithm.dynamicplan;
- public class Knapsack {
- /** 背包重量 */
- private int weight;
- /** 背包物品价值 */
- private int value;
- /***
- * 构造器
- */
- public Knapsack(int weight, int value) {
- this.value = value;
- this.weight = weight;
- }
- public int getWeight() {
- return weight;
- }
- public int getValue() {
- return value;
- }
- public String toString() {
- return "[weight: " + weight + " " + "value: " + value + "]";
- }
- }
背包问题求解:
- /**
- * 求解背包问题:
- * 给定 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)
- * 实现思想: 自底向上的迭代求解 和 基于记忆功能的自顶向下递归
- */
- package algorithm.dynamicplan;
- import java.util.ArrayList;
- public class KnapsackProblem {
- /** 指定背包 */
- private Knapsack[] bags;
- /** 总承重 */
- private int totalWeight;
- /** 给定背包数量 */
- private int n;
- /** 前 n 个背包,总承重为 totalWeight 的最优值矩阵 */
- private int[][] bestValues;
- /** 前 n 个背包,总承重为 totalWeight 的最优值 */
- private int bestValue;
- /** 前 n 个背包,总承重为 totalWeight 的最优解的物品组成 */
- private ArrayList<Knapsack> bestSolution;
- public KnapsackProblem(Knapsack[] bags, int totalWeight) {
- this.bags = bags;
- this.totalWeight = totalWeight;
- this.n = bags.length;
- if (bestValues == null) {
- bestValues = new int[n+1][totalWeight+1];
- }
- }
- /**
- * 求解前 n 个背包、给定总承重为 totalWeight 下的背包问题
- *
- */
- public void solve() {
- System.out.println("给定背包:");
- for(Knapsack b: bags) {
- System.out.println(b);
- }
- System.out.println("给定总承重: " + totalWeight);
- // 求解最优值
- for (int j = 0; j <= totalWeight; j++) {
- for (int i = 0; i <= n; i++) {
- if (i == 0 || j == 0) {
- bestValues[i][j] = 0;
- }
- else
- {
- // 如果第 i 个背包重量大于总承重,则最优解存在于前 i-1 个背包中,
- // 注意:第 i 个背包是 bags[i-1]
- if (j < bags[i-1].getWeight()) {
- bestValues[i][j] = bestValues[i-1][j];
- }
- else
- {
- // 如果第 i 个背包不大于总承重,则最优解要么是包含第 i 个背包的最优解,
- // 要么是不包含第 i 个背包的最优解, 取两者最大值,这里采用了分类讨论法
- // 第 i 个背包的重量 iweight 和价值 ivalue
- int iweight = bags[i-1].getWeight();
- int ivalue = bags[i-1].getValue();
- bestValues[i][j] =
- Math.max(bestValues[i-1][j], ivalue + bestValues[i-1][j-iweight]);
- } // else
- } //else
- } //for
- } //for
- // 求解背包组成
- if (bestSolution == null) {
- bestSolution = new ArrayList<Knapsack>();
- }
- int tempWeight = totalWeight;
- for (int i=n; i >= 1; i--) {
- if (bestValues[i][tempWeight] > bestValues[i-1][tempWeight]) {
- bestSolution.add(bags[i-1]); // bags[i-1] 表示第 i 个背包
- tempWeight -= bags[i-1].getWeight();
- }
- if (tempWeight == 0) { break; }
- }
- bestValue = bestValues[n][totalWeight];
- }
- /**
- * 获得前 n 个背包, 总承重为 totalWeight 的背包问题的最优解值
- * 调用条件: 必须先调用 solve 方法
- *
- */
- public int getBestValue() {
- return bestValue;
- }
- /**
- * 获得前 n 个背包, 总承重为 totalWeight 的背包问题的最优解值矩阵
- * 调用条件: 必须先调用 solve 方法
- *
- */
- public int[][] getBestValues() {
- return bestValues;
- }
- /**
- * 获得前 n 个背包, 总承重为 totalWeight 的背包问题的最优解值矩阵
- * 调用条件: 必须先调用 solve 方法
- *
- */
- public ArrayList<Knapsack> getBestSolution() {
- return bestSolution;
- }
- }
背包问题测试:
- package algorithm.dynamicplan;
- public class KnapsackTest {
- public static void main(String[] args) {
- Knapsack[] bags = new Knapsack[] {
- new Knapsack(2,13), new Knapsack(1,10),
- new Knapsack(3,24), new Knapsack(2,15),
- new Knapsack(4,28), new Knapsack(5,33),
- new Knapsack(3,20), new Knapsack(1, 8)
- };
- int totalWeight = 12;
- KnapsackProblem kp = new KnapsackProblem(bags, totalWeight);
- kp.solve();
- System.out.println(" -------- 该背包问题实例的解: --------- ");
- System.out.println("最优值:" + kp.getBestValue());
- System.out.println("最优解【选取的背包】: ");
- System.out.println(kp.getBestSolution());
- System.out.println("最优值矩阵:");
- int[][] bestValues = kp.getBestValues();
- for (int i=0; i < bestValues.length; i++) {
- for (int j=0; j < bestValues[i].length; j++) {
- System.out.printf("%-5d", bestValues[i][j]);
- }
- System.out.println();
- }
- }
- }
- 0/1背包问题的动态规划法求解 —— Java 实现
- 0/1背包问题的动态规划法求解 —— Java 实现
- 0/1背包问题的动态规划法求解 —— Java 实现
- 0/1背包问题的动态规划法求解 —— Java 实现
- 动态规划法——求解0-1背包问题
- 动态规划法——求解0-1背包问题
- 动态规划法求解简单的(0/1)背包问题
- 0——1背包问题动态规划求解
- Java 动态规划求解0-1背包问题
- 0-1背包问题,动态规划求解
- 动态规划求解0-1背包问题
- 0/1背包问题-----动态规划求解
- 动态规划求解0-1背包问题
- 动态规划算法分析及实例——求解完全背包问题(java实现)
- 0-1背包问题及其动态规划求解之二——王晓东的书本解法
- 0/1背包问题的动态规划求解
- 0-1背包问题的动态规划求解
- 动态规划求解背包问题(JAVA实现)
- 字符串替换
- DOS攻击之SYN攻击原理
- Hadoop中Zookeeper,HDFS,Hbase,Hive,Pig的概念介绍与比较
- 可变参数
- 行内元素和块级元素的区别
- 0/1背包问题的动态规划法求解 —— Java 实现
- Microsoft.Practices.Unity 依赖注入
- chm 转 html
- Eclipse Plugin Rcp
- 更换介质:请把标有…… DVD 的盘片插入驱动器“/media/cdrom/”再按回车键“ 解决方法
- Android ramdisk.img 分析、解压和压缩
- android提供了几种在其他线程中访问UI线程的方法。
- linux线程编程
- android调试工具DDMS