Backpack

Given n items with size Ai, an integer m denotes the size of a backpack. How full you can fill this backpack?

If we have 4 items with size [2, 3, 5, 7], the backpack size is 11, we can select [2, 3, 5], so that the max size we can fill this backpack is 10. If the backpack size is 12. we can select [2, 3, 7] so that we can fulfill the backpack.

You function should return the max size we can fill in the given backpack.

经典背包问题的简化版本,这里求的是背包可以装多满,所以物体的价值这里等于体积.

考虑DP的状态,这里不同于Backpack II, 在体积和前i个约束下考虑价值.

可以从两方面考虑:1.将物体的体积当做物体的价值,f[i][j]为取前i个物体,在最大容量为j的情况,可以获得的最大容量. 听起来很矛盾,但是实际非常符合背包问题的特性,即虽然容量在那里,但是你可能就是无法组合到刚刚填满容量的组合.2.将f[i][j]定义为前i个物体能否组成体积j,能为True, 否则为False.

两种的初始化:1.f[0][j] = 0, 2.f[0][0] = True, f[0][j] = False, 注意2这里是探讨能否装满,所以参考Backpack II中的讨论, 初始化要有所不同.

最终答案: 1. f[n][m], 2.因为是dp存储的是能否的状态,所以我们需要从m朝前遍历f[n][j],第一个为True的j就是最大容量.

做法一代码:

class Solution:
    # @param m: An integer m denotes the size of a backpack
    # @param A: Given n items with size A[i]
    # @return: The maximum size
    def backPack(self, m, A):
        dp = [0] * (m+1)
        for i in xrange(len(A)):
            for j in xrange(m, A[i]-1, -1):
                dp[j] = max(dp[j], dp[j-A[i]] + A[i])
        
        return dp[m]

时间复杂度为O(m*n), 空间复杂度为O(m).

做法二java代码,来自九章:

public class Solution {
    /**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with size A[i]
     * @return: The maximum size
     */
    public int backPack(int m, int[] A) {
        boolean f[][] = new boolean[A.length + 1][m + 1];
        for (int i = 0; i <= A.length; i++) {
            for (int j = 0; j <= m; j++) {
                f[i][j] = false;
            }
        }
        f[0][0] = true;
        for (int i = 0; i < A.length; i++) {
            for (int j = 0; j <= m; j++) {
                f[i + 1][j] = f[i][j];
                if (j >= A[i] && f[i][j - A[i]]) {
                    f[i + 1][j] = true;
                }
            } // for j
        } // for i
        
        for (int i = m; i >= 0; i--) {
            if (f[A.length][i]) {
                return i;
            }
        }
        return 0;
    }
}

这个解法没有使用滚动数组优化,如果进行优化,第一个二维for循环可以省略,但是最后一个找最大值的一维循环无法省略.所以做法一的时间上更优.

原文地址:https://www.cnblogs.com/sherylwang/p/5626356.html