完全背包理论基础
有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。
遍历顺序:01背包遍历背包时要倒序遍历,因为物品不能重复使用,而完全背包遍历背包时要正序遍历,因为物品可以重复使用。遍历物品和遍历背包的顺序随便,先遍历谁都可以(对于纯完全背包问题)。先遍历谁无非就是一行一行填还是一列一列填,只要当前格子的前面一个格子有值,就可以推出当前格子的值。
零钱兑换Ⅱ leetcode 518
dp[j]含义:装满容量为j的背包有多少种方法,求的是dp[amount]。
递推公式:dp[j]+=dp[j-coins[i]]; 装满背包有多少种方法都是这个递推公式!
初始化:dp[0]=1,dp[j]=0(j!=0),因为递推公式是累加和,如果dp[0]初始化为0的话,那么后面的数就都是0了。
遍历顺序:先遍历物品再遍历背包得出的是组合数,先遍历背包再遍历物品得出的是排列数!
所以根据本体我们要得是组合数,所以先遍历物品再遍历背包。
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount+1,0);
dp[0]=1;
for(int i=0;i<coins.size();i++){
for(int j=coins[i];j<dp.size();j++){
dp[j]+=dp[j-coins[i]];
}
}
return dp[amount];
}
};
组合总和Ⅳ leetcode 377
和上一题不同,本题求的是排列,只是遍历顺序的不同。先遍历背包,后遍历物品。
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target+1,0);
dp[0]=1;
for(int i=0;i<=target;i++){
for(int j=0;j<nums.size();j++){
if(i>=nums[j]&& dp[i]<INT_MAX-dp[i-nums[j]])
dp[i]+=dp[i-nums[j]];
}
}
return dp[target];
}
};
因为题目要求题目数据保证答案符合 32 位整数范围。
所以递推公式之前加一个if判断,保证dp[i]也就是这一步要推导出的dp[i]=dp[i]+dp[i-nums[j]];在范围内。
爬楼梯进阶版 卡码网 57
dp[j]含义:爬j层楼梯一共有dp[j]种方法
递推公式:dp[j]+=dp[j-i]。
初始化:dp[0]=1,dp[j]=0(j!=0)。
遍历顺序:求排列,所以先遍历背包(爬的楼梯层数)后遍历物品(每次爬的楼梯层数)。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int m,n;
cin>>n>>m;
vector<int> dp(n+1,0);
dp[0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>=j) dp[i]+=dp[i-j];
}
}
cout<<dp[n]<<endl;
}