代码随想录算法训练营第四十六天
KM52. 携带研究材料
题目链接:KM52. 携带研究材料
- 确定dp数组以及下标的含义:j的含义是当前背包的最大容量,dp[j]背包内物品的总价值
- 确定递推公式:背包最大容量固定为j,每个循环尝试在当前最大容量下,把物品往背包里试着放一下,面临2种情况:
- 最大容量不够放入当前选择的物品,背包内最大的价值就是原来的dp[j],
- 最大容量能放下当前选择的物品,价值为dp[j-wights[i]]+values[i],将wights[i]这么多空间价值的物品取出,在把当前物品的价值放进去的总价值,或者不进行这个交换的总价值哪个更大
- dp数组如何初始化:背包容量为0,没法放物品,价值就都是0,
- 确定遍历顺序:完全背包:从小到大,表示可以把同一物品放进背包多次。01背包:从大到小,表示每个物品只能放一次。
- 打印dp数组。
#include <iostream>
#include <vector>
using namespace std;
int main(){
int N;
int V;
cin >>N>>V ;
vector<int> wights(N);
vector<int> values(N);
for(int i = 0;i<N;i++){
cin>>wights[i]>>values[i];
}
vector<int>dp(V+1);
for(int i = 0;i<N;i++){
for(int j = wights[i];j<=V;j++)
dp[j] = max(dp[j],dp[j-wights[i]]+values[i]);
}
cout<<dp[V];
return 0;
};
518. 零钱兑换 II
题目链接:518. 零钱兑换 II
- 确定dp数组以及下标的含义:j为背包的最大容量,dp[j]当容量为j有几种组合方式
- 确定递推公式:dp[j]=dp[j]+dp[j-nums[i]],不放当前数字组成目标值的种类+必须放当前数字组成目标值的种类(为了保证一定放这个值,就要把需要的容量腾出来)
- dp数组如何初始化:容量为0,有一种放法,dp[0] = 1;
- 确定遍历顺序:先遍历物品,再遍历背包容量,求出来的是组合种类;先遍历背包容量再变量物品,求出来每个容量下不同物品排列的种类数。本题属于前者。
- 打印dp数组。
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<=amount;j++){
dp[j]+=dp[j-coins[i]];
}
}
return dp[amount];
}
};
377. 组合总和 Ⅳ
题目链接:377. 组合总和 Ⅳ
- 确定dp数组以及下标的含义:j为背包的最大容量,dp[j]当容量为j有几种组合方式
- 确定递推公式:dp[j]=dp[j]+dp[j-nums[i]],不放当前数字组成目标值的种类+必须放当前数字组成目标值的种类(为了保证一定放这个值,就要把需要的容量腾出来)
- dp数组如何初始化:容量为0,有一种放法,dp[0] = 1;
- 确定遍历顺序:先遍历物品,再遍历背包容量,求出来的是组合种类;先遍历背包容量再变量物品,求出来每个容量下不同物品排列的种类数。本题属于后者。
- 打印dp数组。
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target + 1, 0);
dp[0] = 1;
for (int j = 1; j <= target; j++) {
for (int i = 0; i < nums.size(); i++) {
if (j >= nums[i] && dp[j] < INT_MAX - dp[j - nums[i]]) {
dp[j] += dp[j - nums[i]];
}
}
}
return dp[target];
}
};