NO.88十六届蓝桥杯备战|动态规划-多重背包|摆花(C++)

news2025/4/19 1:59:13
多重背包

多重背包问题有两种解法:

  1. 按照背包问题的常规分析⽅式,仿照完全背包,第三维枚举使⽤的个数;
  2. 利⽤⼆进制可以表⽰⼀定范围内整数的性质,转化成01 背包问题。
    ⼩建议:并不是所有的多重背包问题都能⽤⼆进制优化,⽽且优化版本的代码很⻓。因此,如果时间复杂度允许的情况下,能不优化就不优化
    解法⼀:常规分析
  3. 状态表⽰:
    dp[i][j]表⽰:从前i 个物品中挑选,总重量不超过j 的情况下,最⼤的价值。
    dp[n][m]就是最终结果。
  4. 状态转移⽅程:
    根据第i 个物品选的个数,可以分x[i] + 1种情况:
    a. 选0 个:价值为dp[i - 1][j]
    b. 选1 个:价值为dp[i - 1][j - w[i]] + v[i]
    c. 选2 个:价值为dp[i - 1][j - 2 × w[i]] + 2 × v[i]
    d. …
    e. 选x[i]个:价值为dp[i - 1][j - x[i] × w[i]] + x[i] × v[i]
    因为要的是最⼤价值,所以dp[i][j]等于上述所有情况的最⼤值。但是要注意j-k*w[i]要⼤于等于0,并且不能按照完全背包的⽅式优化。
  5. 初始化:
    全部为0 就不影响最终结果
  6. 填表顺序:
    从上往下每⼀⾏,每⼀⾏从左往右
#include <bits/stdc++.h>
using namespace std;

const int N = 110;

int n, m;
int x[N], w[N], v[N];
int f[N][N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> x[i] >> w[i] >> v[i];
    
    for (int i = 1; i <= n; i++)
        for (int j = m; j >= 0; j--)
            for (int k = 0; k <= x[i] && k * w[i] <= j; k++)
            {
                f[i][j] = max(f[i][j], f[i-1][j - k*w[i]] + k * v[i]);
            }
    cout << f[n][m] << endl;
    
    return 0;
}

空间优化:

#include <bits/stdc++.h>
using namespace std;

const int N = 110;

int n, m;
int x[N], w[N], v[N];
int f[N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> x[i] >> w[i] >> v[i];
    
    for (int i = 1; i <= n; i++)
        for (int j = m; j >= 0; j--)
            for (int k = 0; k <= x[i] && k * w[i] <= j; k++)
            {
                f[j] = max(f[j], f[j - k*w[i]] + k * v[i]);
            }
    cout << f[m] << endl;
    
    return 0;
}

解法⼆:转化成01背包问题
优化⽅式:⽤⼆进制将x[i]个物品分组。
连续的⼆进制数有⼀个性质,就是 2 0 ∼ 2 k 2^{0}\sim 2^k 202k能够表⽰区间[1, 2^(k+1) - 1]⾥⾯所有的整数。⽐如:

  • 1, 2, 4, 8可以表⽰[1, 15]内所有的整数。具体原因可以参考整数的⼆进制表⽰,正好1, 2, 4, 8对应⼆进制表⽰中每⼀位的权值,所以排列组合起来就可以表⽰[1,15]内所有的整数。
  • 同理1, 2, 4 就可以表⽰[1, 7]内所有的整数。
    根据这样⼀个性质,我们就可以把x[i]拆成⼀些⼆进制数再加上多出来的数,这样的⼀组数就可以表⽰[1,x[i]]内所有的整数,问题就变成了01背包
    ⽐如x[i] = 9,w[i] = 2, v[i] = 3
  • 9 = 1 + 2 + 4 + 2 ;
  • 分成4 组,每组的重量和价值分别为(2, 3)、(4, 6)、(8, 12)、(4, 6)
#include <bits/stdc++.h>
using namespace std;

const int N = 110 * 5;

int n, m;
int w[N], v[N], pos;
int f[N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        int x, y, z; cin >> x >> y >> z;
        //2进制拆分
        int t = 1;
        while (x >= t)
        {
            pos++;
            w[pos] = t * y;
            v[pos] = t * z;
            x -= t;
            t *= 2;
        }
        if (x) //处理剩余
        {
            pos++;
            w[pos] = x * y;
            v[pos] = x * z;
        }
    }
    
    //01背包
    for (int i = 1; i <= pos; i++)
        for (int j = m; j >= w[i]; j--)
            f[j] = max(f[j], f[j - w[i]] + v[i]);
    
    cout << f[m] << endl;
    
    return 0;
}
P1077 [NOIP 2012 普及组] 摆花 - 洛谷

题意:每⼀种花可以选[0, a[i]]个,在总数恰好等于m 时的总⽅案数
正好是多重背包求⽅案数的模型,我们可以⽤多重背包的思考⽅式来解决这道题。

  1. 状态表⽰:
    dp[i][j]表⽰:从前i个花中挑选,正好摆放j 个花盆时的⽅案数。
  2. 状态转移⽅程:
    根据第i 种花选的个数k(0 ≤ k ≤ min(j, a[i])) 分情况讨论:
  • 如果当前花选了k 盆,之前的花要去凑够j - k 盆,总的⽅案数就是dp[i - 1][j - k]
  • 因为要的是总⽅案数,所以最终结果应该是k 的变化过程中的状态的总和。
    dp[i][j] = dp[i][j] + dp[i - 1][j - k]
  1. 初始化:
    dp[0][0] = 1 ,相当于起始状态,为了让后续的填表有意义,不然全都是0 。
  2. 填表顺序:
    从上往下每⼀⾏,每⼀⾏从左往右。
    这道题就不能⽤⼆进制优化,因为这道题的背包,限定条件和价值是⼀⼀对应的,并且求的是⽅案数。如果⽤⼆进制优化会统计多余的情况,⽐如:
  • 有两个物品,个数分别是3, 2 ,要凑成总和为4 。
  • 拆分之后为(1, 2)、(1, 1) ,跑⼀遍01 背包之后,结果是 3 ,但是实际情况应该是2 。
  • 原因是1,2,1被统计了2次。但是在实际情况⾥,第⼀个物品全选,第⼆个物品选1个,只属于1种情况,⽽01背包的逻辑会统计两次
#include <bits/stdc++.h>
using namespace std;

const int N = 110, MOD = 1e6 + 7;

int n, m;
int a[N];
int f[N][N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];

    f[0][0] = 1;
    for (int i = 1; i <= n; i++)
    {
        for (int j = m; j >= 0; j--)
        {
            for (int k = 0; k <= j && k <= a[i]; k++)
            {
                f[i][j] = (f[i][j] + f[i-1][j-k]) % MOD;        
            }
        }
    }
    cout << f[n][m] << endl;
    
    return 0;
}

空间优化

#include <bits/stdc++.h>
using namespace std;

const int N = 110, MOD = 1e6 + 7;

int n, m;
int a[N];
int f[N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];

    f[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        for (int j = m; j >= 0; j--)
        {
            for (int k = 1; k <= j && k <= a[i]; k++)
            {
                f[j] = (f[j] + f[j-k]) % MOD;        
            }
        }
    }
    cout << f[m] << endl;
    
    return 0;
}

单独考虑k==0

#include <bits/stdc++.h>
using namespace std;

const int N = 110, MOD = 1e6 + 7;

int n, m;
int a[N];
int f[N][N];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i];

    f[0][0] = 1;
    for (int i = 1; i <= n; i++)
    {
        for (int j = m; j >= 0; j--)
        {
	        f[i][j] = f[i-1][j];
	        
            for (int k = 1; k <= j && k <= a[i]; k++)
            {
                f[i][j] = (f[i][j] + f[i-1][j-k]) % MOD;        
            }
        }
    }
    cout << f[n][m] << endl;
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332714.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爬虫抓包工具和PyExeJs模块

我们在处理一些网站的时候, 会遇到一些屏蔽F12, 以及只要按出浏览器的开发者工具就会关闭甚至死机的现象. 在遇到这类网站的时候. 我们可以使用抓包工具把页面上屏蔽开发者工具的代码给干掉. Fiddler和Charles 这两款工具是非常优秀的抓包工具. 他们可以监听到我们计算机上所…

无人机击落技术难点与要点分析!

一、技术难点 1. 目标探测与识别 小型化和低空飞行&#xff1a;现代无人机体积小、飞行高度低&#xff08;尤其在城市或复杂地形中&#xff09;&#xff0c;雷达和光学传感器难以有效探测。 隐身技术&#xff1a;部分高端无人机采用吸波材料或低可探测设计&#xff0c;进…

8.第二阶段x64游戏实战-string类

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 上一个内容&#xff1a;7.第二阶段x64游戏实战-分析人物属性 string类是字符串类&#xff0c;在计算机中…

Go语言sync.Mutex包源码解读

互斥锁sync.Mutex是在并发程序中对共享资源进行访问控制的主要手段&#xff0c;对此Go语言提供了非常简单易用的机制。sync.Mutex为结构体类型&#xff0c;对外暴露Lock()、Unlock()、TryLock()三种方法&#xff0c;分别用于阻塞加锁、解锁、非阻塞加锁操作&#xff08;加锁失败…

C++实现文件断点续传:原理剖析与实战指南

文件传输示意图 一、断点续传的核心价值 1.1 大文件传输的痛点分析 网络闪断导致重复传输&#xff1a;平均重试3-5次。 传输进度不可回溯&#xff1a;用户无法查看历史进度。 带宽利用率低下&#xff1a;每次中断需从头开始。 1.2 断点续传技术优势 指标传统传输断点续传…

Python贝叶斯回归、强化学习分析医疗健康数据拟合截断删失数据与参数估计3实例

全文链接&#xff1a;https://tecdat.cn/?p41391 在当今数据驱动的时代&#xff0c;数据科学家面临着处理各种复杂数据和构建有效模型的挑战。本专题合集聚焦于有序分类变量处理、截断与删失数据回归分析以及强化学习模型拟合等多个重要且具有挑战性的数据分析场景&#xff0c…

微信小程序 -- 原生封装table

文章目录 table.wxmltable.wxss注意 table.js注意 结果数据结构 最近菜鸟做微信小程序的一个查询功能&#xff0c;需要展示excel里面的数据&#xff0c;但是菜鸟找了一圈&#xff0c;也没发现什么组件库有table&#xff0c;毕竟手机端好像确实不太适合做table&#xff01; 菜鸟…

分布式文件存储系统FastDFS

文章目录 1 分布式文件存储1_分布式文件存储的由来2_常见的分布式存储框架 2 FastDFS介绍3 FastDFS安装1_拉取镜像文件2_构建Tracker服务3_构建Storage服务4_测试图片上传 4 客户端操作1_Fastdfs-java-client2_文件上传3_文件下载4_获取文件信息5_问题 5 SpringBoot整合 1 分布…

ZKmall开源商城服务端验证:Jakarta Validation 详解

ZKmall开源商城基于Spring Boot 3构建&#xff0c;其服务端数据验证采用Jakarta Validation API​&#xff08;原JSR 380规范&#xff09;&#xff0c;通过声明式注解与自定义扩展机制实现高效、灵活的数据校验体系。以下从技术实现、核心能力、场景优化三个维度展开解析&#…

学透Spring Boot — 017. 魔术师—Http消息转换器

本文是我的专栏《学透Spring Boot》的第17篇文章&#xff0c;了解更多请移步我的专栏&#xff1a; 学透 Spring Boot_postnull咖啡的博客-CSDN博客 目录 HTTP请求和响应 需求—新的Media Type 实现—新的Media Type 定义转换器 注册转换器 编写Controller 测试新的medi…

BOE(京东方)旗下控股子公司“京东方能源”成功挂牌新三板 以科技赋能零碳未来

2025年4月8日,BOE(京东方)旗下控股子公司京东方能源科技股份有限公司(以下简称“京东方能源”)正式通过全国中小企业股份转让系统审核,成功在新三板挂牌(证券简称:能源科技,证券代码:874526),成为BOE(京东方)自物联网转型以来首个独立孵化并成功挂牌的子公司。此次挂牌是BOE(京…

Git使用与管理

一.基本操作 1.创建本地仓库 在对应文件目录下进行&#xff1a; git init 输入完上面的代码&#xff0c;所在文件目录下就会多一个名为 .git 的隐藏文件&#xff0c;该文件是Git用来跟踪和管理仓库的。 我们可以使用 tree 命令&#xff08;注意要先下载tree插件&#xff09…

计算机网络——传输层(Udp)

udp UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议 &#xff09;是一种无连接的传输层协议&#xff0c;它在IP协议&#xff08;互联网协议&#xff09;之上工作&#xff0c;为应用程序提供了一种发送和接收数据报的基本方式。以下是UDP原理的详细解释&…

图解Java设计模式

1、设计模式面试题 2、设计模式的重要性 3、7大设计原则介绍 3.1、单一职责原则

wsl2+ubuntu22.04安装blender教程(详细教程)

本章教程介绍,如何在Windows操作系统上通过wsl2+ubuntu安装blender并运行教程。Blender 是一款免费、开源的 ​​3D 创作套件​​,广泛应用于建模、动画、渲染、视频编辑、特效制作等领域。它由全球开发者社区共同维护,支持跨平台(Windows、macOS、Linux),功能强大且完全…

Spring AI Alibaba MCP 市场正式上线!

Spring AI Alibaba 正式上线 MCP 市场&#xff1a;Spring AI Alibaba-阿里云Spring AI Alibaba官网官网。 开发者可以在这里搜索市面上可用的 MCP Server 服务&#xff0c;了解每个服务的实现与接入方法。 MCP 市场是做什么的&#xff1f; Spring AI Alibaba MCP 当前主要提供…

【Hadoop入门】Hadoop生态圈概述:核心组件与应用场景概述

1 Hadoop生态圈概述 Hadoop生态圈是以 HDFS&#xff08;分布式存储&#xff09; 和 YARN&#xff08;资源调度&#xff09; 为核心&#xff0c;围绕大数据存储、计算、管理、分析等需求发展出的一系列开源工具集合。 核心特点&#xff1a; 模块化&#xff1a;各组件专注解决特定…

致远OA —— 表单数据获取(前端)

文章目录 :apple: 业务需求描述 &#x1f34e; 业务需求描述 测试案例&#xff1a; https://pan.quark.cn/s/3f58972f0a27 官网地址&#xff1a; https://open.seeyoncloud.com/v5devCAP/94/355/359/399/405/406.html 需求描述&#xff1a; 点击获取数据接口&#xff0c;…

游戏引擎学习第214天

总结并为当天的任务做好准备 昨天&#xff0c;我们将所有调试控制代码迁移到使用新的调试接口中&#xff0c;但我们没有机会实际启用这些代码。我们做了很多准备工作&#xff0c;比如规划、将其做成宏、并将其放入调试流中&#xff0c;但实际上我们还没有办法进行测试。 今天…

使用stm32cubeide stm32f407 lan8720a freertos lwip 实现udp client网络数据转串口数据过程详解

1前言 项目需要使用MCU实现网络功能&#xff0c;后续确定方案stm32f407 外接lan8720a实现硬件平台搭建&#xff0c;针对lan8720a也是用的比较多的phy&#xff0c;网上比较多的开发板&#xff0c;硬件上都是选用了这个phy&#xff0c;项目周期比较短&#xff0c;选用了这个常用…