首页 > 技术文章 > 背包问题总结

Water2Wine 2020-08-19 14:51 原文

背包问题可以基本上分为01背包,多重背包,完全背包,本质上都可以化为01背包来解决

01背包的递推式:dp[i][j] = Math.max(dp[i - 1][j - weight] + value[i], dp[i - 1][j])

完全背包的递推式:dp[i][j] = Math.max(dp[i][j - weight] + value, dp[i - 1][j])

多重背包的递推式:dp[i][j] = ∑(0-k)Math.max(dp[i - 1][j - k * weight] + k * value[i], dp[i - 1][j])

根据递推式的不同,01背包在空间压缩的代码中逆序生成dp,完全背包顺序生成dp,多重背包可以将k化为多个2的幂及和的差值转换为01背包,如果k足够大,也可以转换为完全背包

    // 01背包
    // dp[i][j] = Math.max(dp[i - 1][j - weight] + value, dp[i - 1][j])
    private static void getValueOfZeroBag(int i, int k) {
        for (int j = W;j >= 1;j--) {
            if (k * weight[i] <= j) {
                sum[j] = Math.max(sum[j], sum[j - k * weight[i]] + k * value[i]);
            }
        }
    }
    // 完全背包
    // dp[i][j] = Math.max(dp[i][j - weight] + value, dp[i - 1][j])
    private static void getValueOfFullBag(int i) {
        for (int j = 1;j <= W;j++) {
            if (weight[i] <= j) {
                sum[j] = Math.max(sum[j], sum[j - weight[i]] + value[i]);
            }
        }
    }
    // 多重背包
    // 递推式可以分别转换为完全背包和01背包
    private static void getValueOfMultiBag(int i) {
        if (weight[i] * count[i] >= W) {
            // 转换为完全背包
            getValueOfFullBag(i);
        } else {
            // 将count[i]分成多个2的幂次方及一个差值
            int m = 1;
            for (;m <= count[i];m *= 2) {
                getValueOfZeroBag(i, m);
            }
            getValueOfZeroBag(i, count[i] - m / 2);
        }
    }

推荐阅读