采药(01背包+滚动数组优化)
题目来源:https://www.luogu.com.cn/problem/P1048
//
题意:01背包板子
//
讲解:二维01背包(b站):【【自制】01背包问题算法动画讲解】https://www.bilibili.com/video/BV1pY4y1J7na?vd_source=edd8d483423d58308aefa72fbec9bd22
//
思路:二维dp:dp[i][j]:表示选择前i种物品,背包容量为j的最优最大价值。
状态转移方程:if(t>=w[i]){ dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]) } else{dp[i][j]=dp[i-1][j]};状态转移方程的由来我就不赘述了,重要的是明白dp的二维表是如何递推的。
//
滚动数组优化:由二维dp可知,每一个都是上一层dp[i-1]可得,滚动数组就是每一次将上一层的dp[i-1][j]的最优解拷贝到dp[i]层。这里注意!!!滚动数组遍历时,容量表里一定是从大到小,你想想,二维dp转移是不是每次都是从头上不选dp[i-1][j]和上一层的前面dp[i-1][j-w[i]],自然一位更新,要后面获取前面的数据,从后面依次向前更新。如果是从小到大,那1号位置更新了,2号位置得到的1号信息更新不是上一层的数据,这样会造成一个物品购买多次。

//
二维dp:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t,m;//t:容量
cin>>t>>m;
int dp[109][1009];
int w[109],v[109];
for(int i=1;i<=m;i++){
cin>>w[i]>>v[i];
}
for(int i=1;i<=m;i++){
for(int j=t;j>=0;j--){
if(j>=w[i]){
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
}
else{
dp[i][j]=dp[i-1][j];
}
}
}
cout<<dp[m][t]<<endl;
return 0;
}
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int dp[1009];
int w[109],v[109];
int main()
{
int t,m;//t:容量
cin>>t>>m;
for(int i=1;i<=m;i++){
cin>>w[i]>>v[i];
}
for(int i=1;i<=m;i++){//物品
for(int j=t;j>=0;j--){//背包
if(j>=w[i]){
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
}
cout<<dp[t]<<endl;
return 0;
}
浙公网安备 33010602011771号