可以参考这篇博文:https://www.baidu.com/link?url=L8KfGu87UT1dX38ZBjBTRDkHOFZwUsWtesJekk1c1C8FH2UqKws4iSb3NvrUkO7jTHdE-Vnzdh7y2O5IUhw7vgPv9Qh-eFEvrQAIKoN5KKK&wd=&eqid=9001344500120700000000036227f42f
题库在这:题库 - AcWing
一、01背包
for(int i=1;i<=n;i++) for(int j=0;j<=m;j++){
dp[i][j]=dp[i-1][j];
if(j-v[i]>=0) dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
}
for(int i=0;i<n;i++) for(int j=m;j>=v[i];j--)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
二、完全背包
for(int i=1;i<=n;i++) for(int j=0;j<=m;j++){
dp[i][j]=dp[i-1][j];
if(j-v[i]>=0) dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);
}
for(int i=0;i<n;i++) for(int j=v[i];j<=m;j++)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
三、多重背包
法一:01背包(O(nmk),准确来讲是 O(nΣki))
for(int i=0;i<n;i++) for(int k=1;k<=s[i];k++) for(int j=m;j>=v[i];j--)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
for(int i=0;i<n;i++) for(int j=m;j>=v[i];j--) for(int k=1;k<=s[i]&&k*v[i]<=j;k++)
dp[j]=max(dp[j],dp[j-k*v[i]]+k*w[i]);
法二:二进制优化的01背包(O(nmlogk),准确来讲是O(nΣlogki))
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
int n,m,dp[200005];
vector<int> v,w;
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
int vv,ww,s;
scanf("%d %d %d",&vv,&ww,&s);
for(int k=1;s;k=k<<1){
k=min(k,s);
s-=k;
v.push_back(vv*k);
w.push_back(ww*k);
}
}
for(int i=0;i<v.size();i++) for(int j=m;j>=v[i];j--)
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
printf("%d\n",dp[m]);
return 0;
}
法三:单调队列优化的01背包(终极模板,O())
四、混合背包问题
五、二维费用的背包问题
六、分组背包问题
七、有依赖的背包问题
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
int n,m,root,v[105],w[105],dp[105][105];
vector<int> sons[105];
void dfs(int i){
for(int j=v[i];j<=m;j++) dp[i][j]=w[i];//想放子树,必先装根
for(int son:sons[i]){
dfs(son);
for(int j=m;j>=v[i];j--)
for(int k=j-1;k>=v[i];k--)//>=v[i]:得从装过根的本轮小包转移过来
dp[i][j]=max(dp[i][j],dp[i][k]+dp[son][j-k]);
}
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
int fa;
scanf("%d %d %d",&v[i],&w[i],&fa);
if(fa==-1) root=i;
else sons[fa].push_back(i);
}
dfs(root);
printf("%d\n",dp[root][m]);//注意这里不要因为习惯错写成 dp[n][m]
return 0;
}