完全背包问题

2.1 题目

有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。放入第 i 种物品
的费用是 Ci,价值是 Wi。求解:将哪些物品装入背包,可使这些物品的耗费的费用总
和不超过背包容量,且价值总和最大。

2.2 基本思路

这个问题非常类似于 01 背包问题,所不同的是每种物品有无限件。也就是从每种
物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取 0 件、取 1 件、取 2
件……直至取 ⌊V /Ci⌋ 件等许多种。
如果仍然按照解 01 背包时的思路,令 F[i, v] 表示前 i 种物品恰放入一个容量为 v
的背包的最大权值。仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

F[i,v] = max{F[i-1,v-kCi]+KWi}, 0<=kCi <=V

或者

F[i,v] = max(F[i-1,v],F[i,v-Ci]+Wi) 与01背包不同之处仅仅在于第二项的i是否可以重复取,遍历时是顺序。

例题:https://leetcode-cn.com/problems/coin-change/

322. 零钱兑换

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

class Solution {
    public int coinChange(int[] coins, int amount) {
        // 完全背包问题
        // dp[i][j] 背包容量为j,前i个元素的最大价值;
        // 定义改成 和为j,前i个元素,的最少个数;
        // result :  dp[M][amount]
        // 转移方程:dp[i][j] = Math.min(dp[i-1][j],dp[i][j-coins[i]]+1);
        int m = coins.length;
        int[][] dp = new int[m+1][amount+1];
        // init
        for(int j=1;j=0){
                    dp[i][j] = Math.min(dp[i-1][j],dp[i][j-coins[i-1]]+1);
                }else{
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        return dp[m][amount]==0x3f3f3f3f? -1: dp[m][amount];
    }
}

转成一维数组:

class Solution {
    public int coinChange(int[] coins, int amount) {
        // 完全背包问题
        // dp[i][j] 背包容量为j,前i个元素的最大价值;
        // 定义改成 和为j,前i个元素,的最少个数;
        // result :  dp[M][amount]
        // 转移方程:dp[i][j] = Math.min(dp[i-1][j],dp[i][j-coins[i]]+1);
        int m = coins.length;
        int[] dp = new int[amount+1];
        // init
        for(int j=1;j

你可能感兴趣的:(完全背包问题)