动态规划——01背包问题

01背包问题是一个经典的动态规划问题,虽然基础,之前做过很多遍,但是长时间不接触算法还是会忘记,故记录一下。


问题定义:

有 N 件物品和一个容量是V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

具体的练习题目见https://www.acwing.com/problem/content/description/2/


解题思路:

1、首先想一下暴力做法怎么解01背包:

每个物品有选与不选两种状态,用回溯算法遍历全部的可能性,时间复杂度也就是O(2^n)

2、dp数组的含义

首先明确二维dp数组的思路,然后可以优化为一维dp数组的做法

dp[i][j]表示:第[1,i]物品任取放入容量为j的背包中的最大价值

3、dp数组的大小

建议设置为dp[n+1][v+1],这样子不用对首行首列单独初始化

4、状态转移方程

dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i-1]]+w[i-1])

4、双重for循环的遍历先后(先for物品 还是 先for容量)

结论:

对于二维dp数组,先物品/先容量 都可以,因为dp[i][j]都是由上方和左上方得来的

对于一维dp数组(滚动数组),就只能先物品才行


代码:

二维dp:

复制代码
#include<iostream>
#include<vector>
using namespace std;
int main(){
    int n,v;
    cin>>n>>v;
    vector<int> vol(n);
    vector<int> value(n);
    for(int i=0;i<n;i++){
        cin>>vol[i]>>value[i];
    }
    vector<vector<int>> dp(n+1,vector<int>(v+1));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=v;j++){
            if(j>=vol[i-1])dp[i][j]=max(dp[i-1][j],dp[i-1][j-vol[i-1]]+value[i-1]);
            else dp[i][j]=dp[i-1][j];
        }
    }
    cout<<dp[n][v];
    return 0;
}
复制代码

一维dp:

复制代码
#include<iostream>
#include<vector>
using namespace std;
int main(){
    int n,v;
    cin>>n>>v;
    vector<int> vol(n);
    vector<int> value(n);
    for(int i=0;i<n;i++){
        cin>>vol[i]>>value[i];
    }
    vector<int> dp(v+1);
    for(int i=1;i<=n;i++){
        for(int j=v;j>=vol[i-1];j--){
            dp[j]=max(dp[j],dp[j-vol[i-1]]+value[i-1]);
        }
    }
    cout<<dp[v];
    return 0;
}
复制代码

 

posted @   blazerrr  阅读(139)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示