昆明网络建站公司株洲做网站 省心磐石网络
学习资料:代码随想录
文中含大模型生成内容
完全背包
52. 携带研究材料(第七期模拟笔试)
相比于之前的一个物品只能放一次,这次一个物品可以放多次了
递推公式变成了dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);在计算不放该物品有几种方法时,只把该物品的空间让开就可以了
这是二维,先遍历背包还是物品都行
#include <iostream>
#include <vector>
using namespace std;int main(){
int n,v;
cin>>n>>v;vector<int> weight(n,0);
vector<int> value(n,0);for(int i=0;i<n;i++){cin>>weight[i]>>value[i];
}vector<vector<int>> dp(n,vector<int>(v+1,0));for(int j=value[0];j<=v;j++){dp[0][j] = ((j/weight[0])*value[0]);
}for(int i=1;i<n;i++){for(int j=0;j<=v;j++){if(j<weight[i]) dp[i][j] = dp[i-1][j];else{dp[i][j] = max(dp[i-1][j],dp[i][j-weight[i]]+value[i]);}}
}
cout<<dp[n-1][v]<<endl;
return 0;
}
压缩到一维直接借用代码随想录的回答:
将上一层dp[i-1] 的那一层拷贝到 当前层 dp[i] ,那么 递推公式由:dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i])
变成: dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i])
这里有录友想,这样拷贝的话, dp[i - 1][j] 的数值会不会 覆盖了 dp[i][j] 的数值呢?
并不会,因为 当前层 dp[i][j] 是空的,是没有计算过的。
变成 dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i])
我们压缩成一维dp数组,去掉 i 层数维度。
即该点还没计算,仍是上一层的值
这道题求价值,对于一维先遍历谁也是无所谓的。
但是,无论二维还是一维,j倒序遍历不行,因为要用到本层的j了。(这里我没模拟,但感觉应该是对的)
一维:
#include <iostream>
#include <vector>
using namespace std;int main(){
int n,v;
cin>>n>>v;vector<int> weight(n,0);
vector<int> value(n,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=0;j<=v;j++){if(j>=weight[i]){dp[j] = max(dp[j],dp[j-weight[i]]+value[i]);}}
}
cout<<dp[v]<<endl;
return 0;
}
518.零钱兑换II
力扣题目链接
求有几种方法
class Solution {
public:int change(int amount, vector<int>& coins) {// 定义vector<vector<uint64_t>> dp(coins.size(),vector<uint64_t>(amount+1,0));// 初始化for(int i=0;i<coins.size();i++){ //遇到重定义的报错先排查一下是不是i后面写的逗号dp[i][0] = 1;}for(int j=coins[0];j<=amount;j++){if(j%coins[0]==0) dp[0][j] = 1; }// 遍历for(int i =1;i<coins.size();i++){for(int j=1;j<=amount;j++){if(j<coins[i]) dp[i][j] = dp[i-1][j];else{dp[i][j] = dp[i-1][j]+dp[i][j-coins[i]];}}}return dp[coins.size()-1][amount]; }
};
对于一维,就只能先遍历物品了。为什么二维可以先遍历背包而一维不行?j-coins可能会被覆盖掉,举例coin=1,2,amount=3,根据递推公式dp[j]+=dp[j-coins[i]]和dp[i][j]=dp[i-1][j]+dp[i][j-coins[i]]对比来看,外层是j,一维在物品0时用的j-coins[i]是处理过其他物品后的dp值
class Solution {
public:int change(int amount, vector<int>& coins) {// 定义vector<uint64_t> dp(amount+1,0);// 初始化for(int j=0;j<=amount;j++){if(j%coins[0]==0) dp[j] = 1; }// dp[0] = 1;// 遍历for(int i =1;i<coins.size();i++){for(int j=0;j<=amount;j++){if(j>=coins[i]){dp[j] = dp[j]+dp[j-coins[i]];}}}return dp[amount]; }
};
377. 组合总和 Ⅳ
力扣题目链接
求的是排列数,这时就是一维先遍历背包求得的了,让它帮我模拟一下:
感觉这里就暂时摒弃和求组合的方法的比较,单纯从求排列的角度去理解更清晰
class Solution {
public:int combinationSum4(vector<int>& nums, int target) {vector<uint64_t> dp(target+1,0);dp[0] = 1;for(int j=0;j<=target;j++){for(int i =0;i<nums.size();i++){if(j>=nums[i]) dp[j]=dp[j]+dp[j-nums[i]];}} return dp[target];}
};
70. 爬楼梯(进阶版)
卡码网:57. 爬楼梯
相当于求的还是方法数
物品重量就是台阶数
#include <iostream>
#include <vector>using namespace std;int main(){int n,m;
cin>>n>>m;vector<int> dp(n+1,0);dp[0]=1;
for(int j=0;j<=n;j++){for(int i=1;i<=m;i++){if(j>=i) dp[j] +=dp[j-i]; }
}cout<<dp[n];return 0;
}