多重背包问题(一)

简介: AcWing算法提高课内容,本文讲解 动态规划

前言

AcWing算法提高课内容,本文讲解 动态规划

本篇包括以下题目:

⭐️ 多重背包问题 I

⭐️ 多重背包问题 II

⭐️ 多重背包问题 III

⭐️ AcWing 1019. 庆功会

写博客有哪里不完善的地方或者有哪里表达错误希望大家提出来,博主会立即改正!望大家海涵



多重背包问题 I

题目要求

题目描述:

image.png

输入格式:

image.png

输出格式:

输出一个整数,表示最大价值。

数据范围:

image.png

输入样例:

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

思路分析

数据范围很小,暴力枚举即可,不需要过多操作,f[i][j]代表的是只从前 i 件物品中选,且总体积不超过 j的价值最大值。

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[N][N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
    {
        int v, w, s;
        cin >> v >> w >> s;
        for (int j = 0; j <= m; j ++ )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[i][j] = max(f[i][j], f[i - 1][j - k * v] + k * w);
    }
    cout << f[n][m] << endl;
    return 0;
}

代码优化

image.png

滚动数组


#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[2][N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
    {
        int v, w, s;
        cin >> v >> w >> s;
        for (int j = 0; j <= m; j ++ )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[i & 1][j] = max(f[i & 1][j], f[(i - 1) & 1][j - k * v] + k * w);
    }
    cout << f[n & 1][m] << endl;
    return 0;
}

拷贝数组

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[N], g[N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
    {
        int v, w, s;
        cin >> v >> w >> s;
        memcpy(g, f, sizeof f);
        for (int j = 0; j <= m; j ++ )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[j] = max(f[j], g[j - k * v] + k * w);
    }
    cout << f[m] << endl;
    return 0;
}

逆循环优化

逆循环的优化方式和 01 背包的优化是相同的,原理也是一致的,对于体积逆序枚举即可实现,这样的优化方法可真正实现仅用一维数组表示二维变量:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int f[N];
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ )
    {
        int v, w, s;
        cin >> v >> w >> s;
        for (int j = m; ~j; j -- )
            for (int k = 0; k <= s && k * v <= j; k ++ )
                f[j] = max(f[j], f[j - k * v] + k * w);
    }
    cout << f[m] << endl;
    return 0;
}

多重背包问题 II

题目要求

题目描述:

image.png

输入格式:

image.png

输出格式:

输出一个整数,表示最大价值。

数据范围:

image.png

输入样例:

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10

思路分析

image.png

#include <iostream>
using namespace std;
int main()
{
    int i, cnt = 1, temp = 0;
    for (i = 1; temp <= 2000; i ++ )
    {
        temp += cnt;
        cnt *= 2;
    }
    cout << i << endl;
    return 0;
}

运行结果为:12 ,即我们需要开的数组大小就为:12 × 1000 + 10 = 12010

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010, M = 12010;
int v[M], w[M];
int f[N];
int main()
{
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int v1, w1, s;
        cin >> v1 >> w1 >> s;
        int t = 1;
        while (t <= s)
        {
            cnt ++;
            v[cnt] = t * v1;
            w[cnt] = t * w1;
            s -= t;
            t *= 2;
        }
        if (s)
        {
            cnt ++;
            v[cnt] = s * v1;
            w[cnt] = s * w1;
        }
    }
    n = cnt;
    for (int i = 1; i <= n; i ++ )
        for (int j = m; j >= v[i]; j -- )
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    cout << f[m] << endl;
    return 0;
}


#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010, M = 12010, K = 1010;
int v[M], w[M];
int f[K][N];
int main()
{
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    for (int i = 1; i <= n; i ++ )
    {
        int v1, w1, s;
        cin >> v1 >> w1 >> s;
        int t = 1;
        while (t <= s)
        {
            cnt ++;
            v[cnt] = t * v1;
            w[cnt] = t * w1;
            s -= t;
            t *= 2;
        }
        if (s)
        {
            cnt ++;
            v[cnt] = s * v1;
            w[cnt] = s * w1;
        }
    }
    n = cnt;
    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 - 1][j - v[i]] + w[i]);
        }
    cout << f[n][m] << endl;
    return 0;
}

代码优化

既然是转换为了 01背包问题,故我们可以使用 01背包问题优化的思维去优化我们的空间(倒着for循环体积)




目录
相关文章
|
供应链 前端开发 JavaScript
Java开源进销存系统源码,支持手机APP扫码进出库
管店云主要应用于零售门店、商贸批发、生产工厂等行业领域,并可定制开发以满足各行各业的特定需求。管店云包括电脑端和手机APP端,APP支持扫码进出库,操作非常方便。
533 0
Java开源进销存系统源码,支持手机APP扫码进出库
|
数据库
elementUi使用dialog的进行信息的添加、删除表格数据时进行信息提示。删除或者添加成功的信息提示(SpringBoot+Vue+MybatisPlus)
这篇文章介绍了如何在基于SpringBoot+Vue+MybatisPlus的项目中使用elementUI的dialog组件进行用户信息的添加和删除操作,包括弹窗表单的设置、信息提交、数据库操作以及删除前的信息提示和确认。
elementUi使用dialog的进行信息的添加、删除表格数据时进行信息提示。删除或者添加成功的信息提示(SpringBoot+Vue+MybatisPlus)
|
存储 算法 Java
深入解析 Java 数据结构:红黑树的特点与应用
红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,它在 Java 编程中扮演着重要的角色,用于高效地存储和管理数据。红黑树的特点使其在查找、插入和删除操作中保持相对平衡,从而提供了稳定且高效的性能。本文将深入探讨红黑树的特点、用法、实现方式以及在实际应用中的优势。
|
Linux BI 数据处理
在Linux中,如何使用awk和sed进行文本处理?
在Linux中,如何使用awk和sed进行文本处理?
Cannot resolve method ‘success‘ in ‘Result‘
Cannot resolve method ‘success‘ in ‘Result‘
CNN+GRU的网络攻击检测识别详细教学
CNN+GRU的网络攻击检测识别详细教学
309 0
CNN+GRU的网络攻击检测识别详细教学
|
C++
C++如何进行sort的使用——C++如何进行排序
C++如何进行sort的使用——C++如何进行排序
500 0
|
机器学习/深度学习 人工智能 自然语言处理
深度学习原理篇 第一章:transformer入门
简要介绍词向量和transformer原理。
565 1
element-ui的upload组件的clearFiles方法的调用
element-ui的upload组件的clearFiles方法的调用
802 0
|
机器学习/深度学习 数据可视化 算法
【机器学习入门与实践】数据挖掘-二手车价格交易预测(含EDA探索、特征工程、特征优化、模型融合等)
【机器学习入门与实践】数据挖掘-二手车价格交易预测(含EDA探索、特征工程、特征优化、模型融合等)