完全背包
完全背包的状态是由上一个状态和左边的状态推出来的,因此先遍历背包,还是先遍历物品都可以。
完全背包例题
#include<iostream>
#include<vector>
using namespace std;
void bagvalue(vector<int> weight, vector<int> value, int N);
int main(){
vector<int> weight;
vector<int> value;
int n,v;
cin>>n>>v;
for(int i = 0; i < n; i++){
int w,v;
cin>>w>>v;
weight.push_back(w);
value.push_back(v);
}
bagvalue(weight, value, v);
return 0;
}
void bagvalue(vector<int> weight, vector<int> value, int N){
vector<int> dp(N + 1, 0);
for(int i = 0; i < weight.size(); i++){
for(int j = 0; j <= N; j++){
if(j >= weight[i])
dp[j] = max(dp[j - weight[i]] + value[i], dp[j]);
}
}
cout<<dp[N]<<endl;
}
零钱兑换II
完全背包的应用
dp[j] 代表容量为j 的背包,最多有dp[j]种方案。
递推公式 dp[j] = dp[j] + dp[j - nums[i]] 表示不放这个物品一共多上种方法 + 放入这个物品又有多少种方法
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1);
dp[0] = 1;
for(int i = 0; i < coins.size(); i++){
for(int j = 0; j <= amount; j++){
if(j >= coins[i])
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
组合总和IV
和上一题类似,但不完全相同,上一题是组合问题,这一次是排列问题。
因此不得不先遍历背包,再遍历物品。
本质在于dp[i][j] = dp[i - 1][j - nums[i]] + dp[i][j - nums[i]] + + dp[i - 1][j];
当使用一维数组的时候,先遍历列,再遍历行,就dp[j]就相当于dp[i - 1][j - nums[i]] + dp[i][j - nums[i]]了。
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target + 1);
dp[0] = 1;
for(int j = 0; 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];
}