完全背包问题模板

点击查看代码
/*
完全背包

题目:https://ac.nowcoder.com/acm/problem/226516

2.讲解算法原理
        1.状态表示
            f[i][j] 表示:从f[i][j]表示: 从[1, i]区间中挑选, 总体积不超过j的情况下, 所有选法下, 最大价值

        2.状态转移方程
                        不选i  -->  f[i - 1][j]
            f[i][j]     选1个  -->  f[i - 1][j - v[i]] + w[i]
                        选2个  -->  f[i - 1][j - 2*v[i]] + w[i]
                        选k个  -->  f[i - 1][j - k*v[i]] + w[i]  j >= k*v[i]

                要三重循环来解决

            优化状态转移方程
                原: f[i][j] = max(f[i-1][j], f[i-1][j-v[i]] + w[i], f[i-1][j-2*v[i]] + 2w[i], ......);
                    f[i][j - v[i]] = max(f[i-1][j-v[i]], f[i-1][j-2*v[i]] + w[i], f[i-1][j-3*v[i]] + 2w[i], .....);

                所以: f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
                    
            3.初始化

            4.填表顺序
                从上往下每一行
                每一行从左往右

            5.最终结果
                f[n][v]

            6.空间优化
                空间优化上:
                    01 背包: 第二层for循环 -> 从大到小
                    完全背包: 第二层for循环 ->  从小到大
                    
*/

#include <iostream>
#include <cstring>
using namespace std;

const int N = 1010;
int v[N], w[N];
int f[N][N];

int main(){
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    for(int i = 1; i <= n; i++){
        for(int j = 0; j <= m; j++){
            f[i][j] = f[i-1][j];
            if(j >= v[i])
                f[i][j] = max(f[i-1][j], f[i][j - v[i]] + w[i]);
        }
    }
    cout << f[n][m] << endl;
    // memset:将f数组所有字节赋值为-0x3f(十六进制),等价于十进制的-1061109568
    // 作用:初始化所有状态为“不可达”(表示无法恰好装满该容量)
    memset(f, -0x3f, sizeof(f));
    f[0][0] = 0;// 只有“前0件物品,容量0”的状态是可达的(价值为0)
    
    for(int i = 1; i <= n; i++){
        for(int j = 0; j <= m; j++){
            f[i][j] = f[i-1][j];
            if(j >= v[i])
                // 状态2:选第i件物品(完全背包可重复选,所以用f[i][j-v[i]]而非f[i-1][j-v[i]])
                // max比较:不选当前物品 vs 选当前物品,取价值更大的那个
                f[i][j] = max(f[i-1][j], f[i][j - v[i]] + w[i]);
        }
    }
    if(f[n][m] < 0) cout << 0 << endl;
    else cout << f[n][m] << endl;
    
}


#include <iostream>
#include <algorithm> // max函数需要
using namespace std;

const int N = 1010;
int v[N], w[N]; // v[i]:物品体积,w[i]:物品价值
int f[N];       // 一维数组:f[j]表示容量为j的背包的最大价值

int main(){
    int n, m;   // n:物品数,m:背包容量
    cin >> n >> m;
    
    // 输入物品体积和价值
    for(int i = 1; i <= n; i++){
        cin >> v[i] >> w[i];
    }
    
    // ========== 完全背包一维优化核心 ==========
    for(int i = 1; i <= n; i++){          // 遍历每件物品
        // 第二层循环:从小到大(j从v[i]到m),允许重复选当前物品
        for(int j = v[i]; j <= m; j++){
            // 状态转移:f[j] = max(不选当前物品, 选当前物品)
            // 不选:f[j](继承上一轮i-1的结果)
            // 选:f[j - v[i]] + w[i](当前层已更新的新值,允许重复选)
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }
    }
    
    cout << f[m] << endl; // 最终结果:容量m的最大价值
    return 0;
}
posted @ 2026-03-14 10:02  无酒无剑  阅读(3)  评论(0)    收藏  举报