题目链接:52. 携带研究材料(第七期模拟笔试) (kamacoder.com)
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,v;
cin>>n>>v;
vector<int> dp(v+1,0);
vector<int> weight(n,0);
vector<int> val(n,0);
for(int i=0;i<n;i++){
cin>>weight[i]>>val[i];
}
for(int i=0;i<n;i++){
for(int j=0;j<dp.size();j++){
if(j>=weight[i]) dp[j]=max(dp[j],dp[j-weight[i]]+val[i]);
}
}
cout<<dp[v]<<endl;
return 0;
}
和01背包差不多,滚动数组01背包是第一层从前到后,第二层循环从后到前。这个完全背包两个循环都是从前到后。
题目链接:518. 零钱兑换 II - 力扣(LeetCode)
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];
}
};
跟之前做的一道题有点相似,也是累加的,区别是01背包和完全背包。
题目链接:377. 组合总和 Ⅳ - 力扣(LeetCode)
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(nums[j]<=i && dp[i] < INT_MAX - dp[i - nums[j]])dp[i]+=dp[i-nums[j]];
}
}
return dp[target];
}
};
在动态规划:518.零钱兑换II (opens new window)中就已经讲过了。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
如果把遍历nums(物品)放在外循环,遍历target的作为内循环的话,举一个例子:计算dp[4]的时候,结果集只有 {1,3} 这样的集合,不会有{3,1}这样的集合,因为nums遍历放在外层,3只能出现在1后面!
所以本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。
这题对哪个循环在外层还是很有讲究的。