AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 1019. 庆功会【多重背包朴素版】    原题链接    简单

作者: 作者的头像   一只野生彩色铅笔 ,  2021-06-17 18:15:13 ,  所有人可见 ,  阅读 5190


38


9

最近在补全提高课所有题目的题解,宣传一下汇总的地方提高课题解补全计划

题目描述

一共有 $n$ 种奖品,$m$ 元现金

对于第 $i$ 种奖品,其 价格 为 $v_i$,价值 为 $w_i$,数量 为$s_i$

制定一个购买 方案,使得该方案的总价值 最大

分析

物品个数为 $n$,总体积为$m$,初步识别是一个 背包问题

观察到每个物品有 数量限制,断定该题是 多重背包问题

本题是一道 多重背包 的裸题

本篇题解,只展示 多重背包 的朴素优化和分析,关于 单调队列优化 可以看这篇博客
AcWing 6. 多重背包问题 III【单调队列优化+图示】

不多废话,我们直接上 闫氏DP分析法

闫氏DP分析法

初始状态:f[0][0]
目标状态:f[n][m]

IMG_4AD8EC65CFE1-1.jpeg

Code(朴素写法)

时间复杂度:$O(n \times m \times s)$

空间复杂度:$O(n \times m)$

#include <iostream>

using namespace std;

const int N = 510, M = 6010;

int n, m;
int v[N], w[N], s[N];
int f[N][M];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = 0; j <= m; ++ j)
        {
            for (int k = 0; k <= s[i]; ++ k)
            {
                if (j - k * v[i] >= 0)
                {
                    f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
                }
            }
        }
    }
    cout << f[n][m] << endl;
    return 0;
}

朴素优化方式

同 01背包 ,对于第 i 阶段的状态更新只会用到第 i-1 阶段的状态

因此可以采用 滚动数组 或者根据状态更新的顺序,直接压缩成 一维 的优化方式

时间复杂度:$O(n \times m \times s)$

空间复杂度:$O(m)$

一维优化方式

#include <iostream>

using namespace std;

const int N = 510, M = 6010;

int n, m;
int v[N], w[N], s[N];
int f[M];

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) cin >> v[i] >> w[i] >> s[i];
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = m; j >= v[i]; -- j)
        {
            for (int k = 0; k <= s[i]; ++ k)
            {
                if (j - k * v[i] >= 0)
                {
                    f[j] = max(f[j], f[j - k * v[i]] + k * w[i]);
                }
            }
        }
    }
    cout << f[m] << endl;
    return 0;
}

4 评论


用户头像
谭sir   2023-05-22 14:41         踩      回复

还是有个小小的疑问,就是如何保证买到的物品数量恰好是n呢?

用户头像
wyn666   2023-07-21 17:45         踩      回复

没要求吧


用户头像
徐徐的秋风   2022-09-18 02:52         踩      回复

状态转移分析的时候 不选i的时候还是f[i-1,j] 到了写代码的时候就是f[i,j]了。。。

用户头像
nope_ck   2022-10-27 18:58         踩      回复

因为在k == 0的时候就已经把f[i - 1][j]的值给f[i][j]了

用户头像
nope_ck   2022-10-27 18:58         踩      回复

因为在k == 0的时候就已经把f[i - 1][j]的值给f[i][j]了

用户头像
nope_ck   2022-10-27 18:58         踩      回复

因为在k == 0的时候就已经把f[i - 1][j]的值给f[i][j]了

用户头像
nope_ck   2022-10-27 18:58         踩      回复

因为在k == 0的时候就已经把f[i - 1][j]的值给f[i][j]了


用户头像
gtt   2022-04-04 22:37         踩      回复

Orz


用户头像
糖豆   2022-01-26 08:51         踩      回复

请教一下,为什么二维的j 需要从0开始,不可以从v[i]开始呢?而一维的却是到v[i]结束?

用户头像
一只野生彩色铅笔   2022-01-26 09:14         踩      回复

第一个问题,和转移需要的状态有关,这个不知道的话,可以复习一下01背包优化
第二个问题,因为选 $0$ 个可以不用更新,所以到 v[i] 结束

用户头像
糖豆   2022-01-26 09:44    回复了 一只野生彩色铅笔 的评论         踩      回复

谢谢巨巨大佬,我去复习下~

用户头像
nope_ck   2022-05-05 17:42    回复了 一只野生彩色铅笔 的评论         踩      回复

第一个问题 因为 dp[i][0]到v[i]还需要被dp[i-1][0]给赋初值
第二个问题,因为一维数组的状态每一轮都是由上一轮先更新然后就不需要在更新那些小于v[i]的情况


用户头像
Tilbur   2021-06-17 18:17         踩      回复

铅笔哥 tql!

用户头像
一只野生彩色铅笔   2021-06-17 18:18         踩      回复

光头哥 tql!


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息