动态规划本质理解:01背包问题

题目描述:01背包问题 w:重量 v:价值 cap:承重

参考代码:

package Dp;

import org.junit.Test;

/**
 * 01背包问题 w:重量 v:价值 cap:承重
 *
 * @author Tongkey
 */
public class Backpack {
    public int[][] result;

    /**
     * 递归解法,时间复杂度为O(2^n)
     *
     * @param w
     *            重量
     * @param v
     *            价值
     * @param cap
     *            承重
     * @param n
     *            数量
     * @param curCap
     *            当前的重量 总重量 = 当前的重量+剩余的重量
     * @param index
     *            当前的下标值
     * @return
     */
    public int maxValueRe(int[] w, int[] v, int cap, int n, int curCap,
            int index) {
        if (curCap > cap) {
            return 0;
        }
        if (index >= n) {
            return 0;
        }
        return Math.max(maxValueRe(w, v, cap, n, curCap + w[index], index + 1)
                + v[index], maxValueRe(w, v, cap, n, curCap, index + 1));
    }

    /**
     * 备忘录解法(自顶向下),时间复杂度O(n*cap),空间复杂度O(n*cap)
     *
     * @param w
     *            重量
     * @param v
     *            价值
     * @param cap
     *            承重
     * @param n
     *            数量
     * @param curCap
     *            当前的重量 总重量 = 当前的重量+剩余的重量
     * @param index
     *            当前的下标值
     * @return
     */
    public int maxValueMemory(int[] w, int[] v, int cap, int n, int curCap,
            int index) {
        if (curCap > cap) {
            return 0;
        }
        if (index >= n) {
            return 0;
        }
        if (result[index][curCap] > 0) {
            return result[index][curCap];
        }
        result[index][curCap] = Math
                .max(maxValueRe(w, v, cap, n, curCap + w[index], index + 1)
                        + v[index], maxValueRe(w, v, cap, n, curCap, index + 1));
        return result[index][curCap];
    }

    @Test
    public void testMaxValueMemory(){
        int[] w = { 42, 25, 30, 35, 42, 21, 26, 28 };
        int[] v = { 261, 247, 419, 133, 391, 456, 374, 591 };
        int n = 8;
        int cap = 297;
        result = new int[n][cap + 1];
        int maxValueRe = maxValueMemory(w, v, cap, n, 0, 0);
        System.out.println(maxValueRe);
        System.out.println("----------------------");
    }

    /**
     * 自底向上(非递归写法),时间复杂度O(n*cap),空间复杂度O(n*cap)
     *
     * @param w
     * @param v
     * @param cap
     * @param n
     * @param curCap
     * @param index
     * @return
     */
    public int maxValueDp(int[] w, int[] v, int cap, int n, int curCap,
            int index) {

        result[0][0] = 0;
        // 第一行
        for (int i = 1; i <= cap; i++) {
            if (i >= w[0])
                result[0][i] = v[0];
        }
        // 第一列
        for (int i = 1; i < n; i++) {
            result[i][0] = 0;
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= cap; j++) {
                // 默认值,不取index当前的重量值
                result[i][j] = result[i - 1][j];
                if (j >= w[i])
                    result[i][j] = Math.max(result[i][j], result[i - 1][j
                            - w[i]]
                            + v[i]);
            }
        }
        return result[n - 1][cap];
    }

    /**
     * 自底向上(利用滚动数组非递归写法优化),时间复杂度O(n*cap),空间复杂度O(cap)
     * @param w
     * @param v
     * @param cap
     * @param n
     * @param curCap
     * @param index
     * @return
     */
    public int maxValueDpMod(int[] w, int[] v, int cap, int n, int curCap,
            int index) {

        result[0][0] = 0;
        // 第一行
        for (int i = 1; i <= cap; i++) {
            if (i >= w[0])
                result[0][i] = v[0];
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j <= cap; j++) {
                result[i % 2][j] = result[(i - 1) % 2][j];
                if (j >= w[i])
                    result[i % 2][j] = Math.max(result[i % 2][j],
                            result[(i - 1) % 2][j - w[i]] + v[i]);
            }
        }
        return Math.max(result[0][cap], result[1][cap]);
    }

    /**
     * 把二维数组优化为一维数组版本
     * @param w
     * @param v
     * @param n
     * @param cap
     * @return
     */
    public int maxValueDp2(int[] w, int[] v, int n, int cap) {
        // 给定物品的重量w价值v及物品数n和承重cap
        int[] d = new int[cap + 1];
        for (int i = 0; i < n; i++) {
            for (int j = cap; j >= w[i]; j--) {
                d[j] = Math.max(d[j], d[j - w[i]] + v[i]);
            }
        }
        return d[cap];
    }

    @Test
    public void testMaxValueRe() {
        int[] w = { 42, 25, 30, 35, 42, 21, 26, 28 };
        int[] v = { 261, 247, 419, 133, 391, 456, 374, 591 };
        int n = 8;
        int cap = 297;
        result = new int[2][cap + 1];
        int maxValueRe = maxValueDpMod(w, v, cap, n, 0, 0);
        System.out.println(maxValueRe);
        System.out.println("----------------------");
    }
}
时间: 2024-07-31 04:31:49

动态规划本质理解:01背包问题的相关文章

动态规划三:0-1背包问题

1.问题描述: 一定的物体和一背包,物体i的重量为wi价值为vi,背包的容量为c,求解怎样放使背包的价值最大?则问题可描述为: 2.问题分析: 1)最优子结构: 其中j=c-wiyi 2)递归关系:设最优值为m(i,j),j表示最优容量,i表示可选物品,由最优子结构性质可建立递归式: 3.算法描述:(未优化) 1 #include<iostream> 2 using namespace std; 3 int c[10][100]; 4 int Knap(int m, int n){ 5 int

动态规划专题 01背包问题详解【转】

对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本文力求通俗易懂,无异性,不让读者感到迷惑,引导读者去思考,所以如果你在阅读中发现有不通顺的地方,让你产生错误理解的地方,让你难得读懂的地方,请跟贴指出,谢谢! 初识动态规划 经典的01背包问题是这样的: 有一个包和n个物品,包的容量为m,每个物品都有各自的体积和价值,问当从这n个物品中选择多个物品放

动态规划01背包问题(例子详解)

附上原文地址:http://www.cnblogs.com/sdjl/articles/1274312.html ----第一节----初识动态规划-------- 经典的01背包问题是这样的: 有一个包和n个物品,包的容量为m,每个物品都有各自的体积和价值,问当从这n个物品中选择多个物品放在包里而物品体积总数不超过包的容量m时,能够得到的最大价值是多少?[对于每个物品不可以取多次,最多只能取一次,之所以叫做01背包,0表示不取,1表示取] 为了用一种生动又更形象的方式来讲解此题,我把此题用另一

01背包问题--动态规划解法

从01背包问题理解动态规划 01背包问题具体例子:假设现有容量10kg的背包,另外有3个物品,分别为a1,a2,a3.物品a1重量为3kg,价值为4:物品a2重量为4kg,价值为5:物品a3重量为5kg,价值为6.将哪些物品放入背包可使得背包中的总价值最大? 这个问题有两种解法,动态规划和贪婪算法.本文仅涉及动态规划. 先不套用动态规划的具体定义,试着想,碰见这种题目,怎么解决? 首先想到的,一般是穷举法,一个一个地试,对于数目小的例子适用,如果容量增大,物品增多,这种方法就无用武之地了. 其次

【算法问题】0-1背包问题

0-1背包问题:有一个贼在偷窃一家商店时,发现有n件物品,第i件物品价值vi元,重wi磅,此处vi与wi都是整数.他希望带走的东西越值钱越好,但他的背包中至多只能装下W磅的东西,W为一整数.应该带走哪几样东西?这个问题之所以称为0-1背包,是因为每件物品或被带走:或被留下:小偷不能只带走某个物品的一部分或带走同一物品两次. 在分数(部分)背包问题(fractional knapsack problem)中,场景与上面问题一样,但是窃贼可以带走物品的一部分,而不必做出0-1的二分选择.可以把0-1

【算法导论】0-1背包问题

一.0-1背包问题描述: 已知:小偷在店里偷东西,小偷只带了一个最大承重为W的背包,商店里有N件商品,第i件商品的重量是weight[i],价钱是value[i]. 限制:每种商品只有一件,可以选择拿或者不拿,不能分割,不能只拿一件商品的一部分(所以叫做0-1,0即不拿,1则整个拿走,且一种商品有且只有一件可供拿走) 问题:在不超过背包最大承重的情况下,最多能拿走多少钱的商品. 算导上与0-1背包问题对应的是分数背包问题,分数背包问题中的物品是可以取一部分的,就是说可以拆分的,不像0-1背包中,

01背包问题JAVA实现

在刷华为机试的在线编程,碰到一个类似01背包问题的题目,综合了一些资料,写一些自己的理解 01背包问题就是在有限的称重容量下,求最大价值的问题 假设几个参数: w[i]:第i个物品的重量: p[i]:第i个物品的价值: v[i][j]:表示在前i个物品中,总重量为j时的最大价值: v[i-1][j-w[i]]:表示前i-1个物品中,加入第i个物品后的承重容量下的最大价值: 我们分析:在加入第i件物品前,我们要考虑要不要加进去,不加进去,那么就是v[i][j]=v[i-1][j]:如果加进去,那么

0-1背包问题1

鼓捣好久 终于了然了一些 0-1背包问题描述 有一个窃贼在偷窃一家商店时发现有n件物品,第i件物品价值为vi元,重量为wi,假设vi和wi都为整数.他希望带走的东西越值钱越好,但他的背包中之多只能装下W磅的东西,W为一整数.他应该带走哪几样东西? [注]0-1背包问题中:每件物品或被带走,或被留下,(需要做出0-1选择).小偷不能只带走某个物品的一部分或带走两次以上同一个物品. 采用动态规划算法求解0-1背包问题, 用子问题定义状态:即f[i][ J]表示前i件物品放入一个容量为j的背包可以获得

0-1背包问题的动态规划法与回溯法

一.动态规划 状态转移方程: 1 从前往后: 2 if(j>=w[i]) 3 m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]); 4 else 5 m[i][j]=m[i-1][j]; 6 7 从后往前: 8 if(j>=w[i]) 9 m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]); 10 else 11 m[i][j]=m[i+1][j]; 算法: 1 从前往后: 2 for(int i=1;i<=n;i++)