一、完全背包问题
相较于01背包,完全背包的显著特征是每个物品可以用无数次,遍历顺序也不需要为了保证每个物品只去一次而倒序遍历。
#include<iostream>
#include<vector>
using namespace std;
int main(){
int N,V;
cin>>N>>V;
vector<int>weight(N+1,0);
vector<int>value(N+1,0);
for(int i=0;i<N;i++){
cin>>weight[i]>>value[i];
}
vector<int>dp(V+1,0);
for(int i=0;i<N;i++){
for(int j=weight[i];j<=V;j++){
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
cout<<dp[V]<<endl;
return 0;
}
二、零钱兑换
(一)dp数组含义:dp[j]为凑成j元可以的方法数
(二)递推公式:dp[j]+=dp[j-coins[i]]把数组中第一个元素所能组成的方法数一直加到最后一个元素所能组成的方法数。
(三)初始化:dp[0]=1
(四)完全背包,正向遍历背包,组合问题选择先物品后背包。
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int>dp(amount+1,0);//dp[j]为凑成j元的组合数
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];
}
};
三、组合总和Ⅳ
本题是排列问题,排列问题与组合问题的区别就是遍历顺序不同
(一)dp数组含义:dp[j]为凑成总和为j,可以的方法数
(二)递推公式:dp[j]+=dp[j-nums[i]]把数组中第一个元素所能组成的方法数一直加到最后一个元素所能组成的方法数。
(三)初始化:dp[0]=1
(四)完全背包,正向遍历背包,排列问题先背包后物品
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int>dp(target+1,0);
dp[0]=1;
// for(int i=0;i<nums.size();i++){
// for(int j=nums[i];j<=target;j++){
// dp[j]+=dp[j-nums[i]];
// }
// }
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];
}
};
四、爬楼梯 (完全背包法)
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int>pathlength;
for(int i=0;i<m;i++){
pathlength.push_back(i+1);
}
vector<int>dp(n+1,0);
dp[0]=1;
for(int j=0;j<=n;j++){
for(int i=0;i<m;i++){
if(j>=pathlength[i]){
dp[j]+=dp[j-pathlength[i]];
}
}
}
cout<<dp[n]<<endl;
return 0;
}