C++---背包模型---潜水员(每日一道算法2023.3.13)

这篇具有很好参考价值的文章主要介绍了C++---背包模型---潜水员(每日一道算法2023.3.13)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

注意事项:
本题是"动态规划—01背包"和"背包模型—二维费用的背包问题"的扩展题,优化思路不多赘述,dp思路会稍有不同,下面详细讲解。

题目:
潜水员为了潜水要使用特殊的装备。

他有一个带2种气体的气缸:一个为氧气,一个为氮气。
让潜水员下潜的深度需要各种数量的氧和氮。
潜水员有一定数量的气缸。
每个气缸都有重量和气体容量。
潜水员为了完成他的工作需要特定数量的氧和氮。
他完成工作所需气缸的总重的最低限度的是多少?

例如:
潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:

3 36 120

10 25 129

5 50 250

1 45 130

4 20 119

如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。
你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。

输入格式
第一行有2个整数 m,n。它们表示氧,氮各自需要的量。
第二行为整数 k表示气缸的个数。
此后的 k行,每行包括ai,bi,ci,3个整数。这些各自是:第 i个气缸里的氧和氮的容量及气缸重量。

输出格式
仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。

数据范围
1≤m≤21,
1≤n≤79,
1≤k≤1000,
1≤ai≤21,
1≤bi≤79,
1≤ci≤800

输入:
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
输出:
249
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1010;
int n, m, c;                // 需要的氧气,需要的氮气,气缸的数量
int v1[N], v2[N], w[N];     // v1[i]物品i的氧气量,v2[i]物品i的氮气量,重量
int f[N][N];

int main() {
    cin >> n >> m >> c;
    for (int i = 1; i<=c; i++) cin >> v1[i] >> v2[i] >> w[i]; // 输入每个气缸中包含的氧和氮的数量以及它们各自的重量

    memset(f, 0x3f3f, sizeof f); // 由于我们要求最小值,所以初始化数组f为无穷大
    f[0][0] = 0; // 当选取0个氧气和0个氮气的方案就是0

    //二维费用dp,优化参考01背包
    for (int i = 1; i<=c; i++) {
        for (int j = n; j>=0; j--) {
            for (int k = m; k>=0; k--) {
                //题目所说的是,当方案的v1不小于n,且v2不小于m时,w的最小值,也就是说可能用到超过n和m的物品,也就会出现负数的情况
                //这也就是为什么j>=0,k>=0,而不是j>=v1[i],k>=v2[i]
                //例如f[2][5],也就是需要v1不小于2,v2不小于5,那么如果有一个物品v1是3,v2是4,那么这个物品照样能用只是多出了一些体积但是仍然符合条件
                //就可以转移为f[0][1] + w, 此时就不需要v1了,因为v1满了,只需要看v2即可(也就是负数也能用,换为0即可)。
                f[j][k] = min(f[j][k], f[max(0, j - v1[i])][max(0, k - v2[i])] + w[i]);
            }
        }
    }

    cout << f[n][m];
    return 0;
}

思路:
经典的y式dp法

1.状态表示
f[i][j][k]:考虑前i个物品,体积不小于j,重量不小于k时的所有方案,属性为Min。

v1[i]第i个物品的氧气,v2[i]第i个物品的氮气,w[i]第i个物品的重量

2.状态计算
以 选择/不选择 第i个物品为划分,
1.当不选择第i个物品时:
f[i][j][k] = f[i-1][j][k]
2.当选择第二个物品时:
f[i][j][k] = min(f[i][j][k], f[i-1][j-v1[i]][k-v2[i]] + w[i])

同时由于我们无法开三维数组,那么就将第i维也就是物品维度优化即可,参考01背包的优化方式。

这里还有一点要提醒:
状态表示分析出的是:考虑前i个物品,体积不小于j,重量不小于k时的所有方案,找w的最小值,也就是说可能用到超过jk的物品,也就会出现 j-v1[i]或者k-v2[i]负数的情况。

这也就是为什么j>=0,k>=0而不是j>=v1[i],k>=v2[i]

例如f[2][5],也就是需要物品v1不小于2,v2不小于5,
那么如果有一个物品v1是3,v2是4,那么这个物品照样能用只是多出了一些体积但是仍然符合条件,
就可以转移为f[0][1] + w, 此时就不需要v1了,因为v1满了,只需要看v2即可(负数也能用,换为0即可)。

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流文章来源地址https://www.toymoban.com/news/detail-699680.html

到了这里,关于C++---背包模型---潜水员(每日一道算法2023.3.13)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++---状态压缩dp---愤怒的小鸟(每日一道算法2023.4.19)

    注意事项: 难度警告!这题在NOIP中也算偏难的题,量力而行。 本题为\\\"状态压缩dp—最短Hamilton路径\\\"的扩展题,建议先阅读这篇文章并理解。 本题是\\\"重复覆盖问题\\\"可以使用\\\"Dancing Links\\\"做,但我们这里是用的状态压缩dp来写。 题目: Kiana 最近沉迷于一款神奇的游戏无法自拔。

    2023年04月23日
    浏览(23)
  • C++---树形DP---树的最长路径(每日一道算法2023.5.4)

    注意事项: 本题为\\\"树与图的DFS深度优先遍历—树的重心\\\"的近似题,同时涉及到 单链表模拟邻接表存储图 的操作,建议先理解那篇文章。 题目: 给定一棵树,树中包含 n 个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。 现在请你找到树中的一条最长路径。 换句话

    2024年02月02日
    浏览(26)
  • 每日一道算法题 1

    借鉴文章:Java-敏感字段加密 - 哔哩哔哩 题目描述  给定一个由多个命令字组成的命令字符串; 1、字符串长度小于等于127字节,只包含大小写字母,数字,下划线和偶数个双引号 2、命令字之间以一个或多个下划线_进行分割 3、可以通过两个双引号\\\"\\\"来标识包含下划线_的命令

    2024年02月04日
    浏览(28)
  • 每日一道面试题之什么是反射?

    反射是一种自我观察的能力,在程序运行时,对任意一个类,我们可通过 class、constructor、field、method 四个方法获取该类的各个组成部分,在java程序运行时,对任意类,我们都可通过该类了解到其包含哪些属性和方法,这种 动态获取当前类对象的信息以及动态调用对象方法的

    2024年02月08日
    浏览(37)
  • 每日一道面试题之介绍一下Iterator

    Iterator是Java中的一个接口 , 用于遍历集合(Collection)中的元素 。通过Iterator,可以 按顺序访问集合中的每个元素 ,而无需了解集合的内部实现细节。 通过调用集合的 iterator()方法获取Iterator对象 。例如: 使用 while循环和hasNext()方法判断是否还有下一个元素 。例如: 使用

    2024年02月15日
    浏览(24)
  • 每日一道编程题:计算2的N次方

    任意给定一个正整数N(N=100),计算2的n次方的值。 输入一个正整数N。 输出2的N次方的值。

    2024年01月23日
    浏览(26)
  • 力扣每日一道系列 --- LeetCode 160. 相交链表

    📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构探索 ✅LeetCode每日一道 🌅 有航道的人,再渺小也不会迷途。 LeetCode 160. 相交链表 思路: 首先计算两个链表的长度,然后判断两个链表的尾节点是否相同。如果不同,那么这两个链表就没有交集,返回空;如果相同,那么就

    2024年02月05日
    浏览(26)
  • 力扣每日一道系列 --- LeetCode 206. 反转链表

    📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构探索 ✅LeetCode每日一道 🌅 有航道的人,再渺小也不会迷途。 LeetCode 206. 反转链表 初始化两个指针, cur 和 newhead 。 cur 指向给定的链表头节点, newhead 初始为 NULL 。 在 cur 不为空的情况下,执行循环。 首先,记录下 cur 的下

    2024年02月04日
    浏览(30)
  • 力扣每日一道系列 --- LeetCode 88. 合并两个有序数组

    📷 江池俊: 个人主页 🔥个人专栏: ✅数据结构探索 ✅LeetCode每日一道 🌅 有航道的人,再渺小也不会迷途。 LeetCode 88. 合并两个有序数组 首先创建一个临时数组,其大小为第一个数组的大小(即nums1Size),其作用主要是。 通过循环遍历两个数组,将两个数组元素比较后较

    2024年02月04日
    浏览(36)
  • 每日一道面试题之Collection 和 Collections 有什么区别?

    Collection和Collections是Java集合框架中的两个重要的概念,它们在Java集合框架中扮演不同的角色。 Collection 是 Java集合框架中的一个接口 ,它是 所有集合类的根接口 , 用于操作和管理一组对象 ,Collection接口的常见实现类包括 List、Set和Queue 等,分别定义了不同的存储方式。

    2024年02月16日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包