背包问题(位运算优化、bitset)

news2024/10/27 7:07:55

3180. 执行操作可获得的最大总奖励|

. - 力扣(LeetCode)

给你一个整数数组 rewardValues,长度为 n,代表奖励的值。

最初,你的总奖励 x 为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 

  • 从区间 [0, n - 1] 中选择一个 未标记 的下标 i
  • 如果 rewardValues[i] 大于 你当前的总奖励 x,则将 rewardValues[i] 加到 x 上(即 x = x + rewardValues[i]),并 标记 下标 i

以整数形式返回执行最优操作能够获得的 最大 总奖励。

示例 1:

输入:rewardValues = [1,1,3,3]

输出:4

解释:

依次标记下标 0 和 2,总奖励为 4,这是可获得的最大值。

示例 2:

输入:rewardValues = [1,6,4,3,2]

输出:11

解释:

依次标记下标 0、2 和 1。总奖励为 11,这是可获得的最大值。

提示:

  • 1 <= rewardValues.length <= 2000
  • 1 <= rewardValues[i] <= 2000

这道题需要转变一下思路,因为一般来讲传统的动态规划呢都是直接计算出答案,这道题呢如果直接计算答案你会发现非常难写,那么我们就换一种思路,计算可达的状态。

还是按照背包问题的思路分为选或不选

不选的话就是dp[i][j] = dp[i - 1][j]

选的话要考虑清楚,首先 j 肯定要先大于reward,sum = j - reward,需要保证reward > sum,就推出了j < 2 * reward,至此动态转移方程就出来了

dp[i][j] = dp[i - 1][j]

if(j >= reward && j < 2 * reward) dp[i][j] = dp[i][j - reward] + reward

代码

class Solution {
    static const int N = 2e3 + 10,M = 4e3 + 10;
    bool dp[N][M];
public:
    int maxTotalReward(vector<int>& rewardValues) {
        int n = rewardValues.size();
        if(n == 1) return rewardValues[0];

        sort(rewardValues.begin(),rewardValues.end());
        int v = rewardValues[n - 1] * 2;
        dp[0][0] = true;
        for(int i = 0;i < n;i ++){
            for(int j = v;j >= 0;j --){
                dp[i + 1][j] = dp[i][j];
                if(j >= rewardValues[i] && j < 2 * rewardValues[i]){
                    dp[i + 1][j] = (dp[i + 1][j] || dp[i][j - rewardValues[i]]);
                }
            }
        }
        int res = 0;
        for(int j = 0;j <= v;j ++){
            if(dp[n][j]) res = max(res,j); 
        }
        return res;
    }
};

至于优化到一维dp的话就很简单了

class Solution {
    static const int N = 2e3 + 10,M = 4e3 + 10;
    bool dp[M];
public:
    int maxTotalReward(vector<int>& rewardValues) {
        int n = rewardValues.size();
        if(n == 1) return rewardValues[0];

        sort(rewardValues.begin(),rewardValues.end());
        int v = rewardValues[n - 1] * 2;
        dp[0] = true;
        for(int i = 0;i < n;i ++){
            for(int j = v;j >= 0;j --){
                if(j >= rewardValues[i] && j < 2 * rewardValues[i]){
                    dp[j] = (dp[j] || dp[j - rewardValues[i]]);
                }
            }
        }
        int res = 0;
        for(int j = 0;j <= v;j ++){
            if(dp[j]) res = max(res,j); 
        }
        return res;
    }
};

3181. 执行操作可获得的最大总奖励| |

 

. - 力扣(LeetCode)

给你一个整数数组 rewardValues,长度为 n,代表奖励的值。

最初,你的总奖励 x 为 0,所有下标都是 未标记 的。你可以执行以下操作 任意次 

  • 从区间 [0, n - 1] 中选择一个 未标记 的下标 i
  • 如果 rewardValues[i] 大于 你当前的总奖励 x,则将 rewardValues[i] 加到 x 上(即 x = x + rewardValues[i]),并 标记 下标 i

以整数形式返回执行最优操作能够获得的 最大 总奖励。

示例 1:

输入:rewardValues = [1,1,3,3]

输出:4

解释:

依次标记下标 0 和 2,总奖励为 4,这是可获得的最大值。

示例 2:

输入:rewardValues = [1,6,4,3,2]

输出:11

解释:

依次标记下标 0、2 和 1。总奖励为 11,这是可获得的最大值。

提示:

  • 1 <= rewardValues.length <= 5 * 10^4
  • 1 <= rewardValues[i] <= 5 * 10^4

那如果数据范围变大了,需要怎么考虑优化呢?首先我们已经推理出来了,在i >= reward && i < 2 * reward的条件下:dp[i] = dp[i] | dp[i - reward]

那么如果一个个去枚举在这种打范围的数据下会超时,考虑用每次计算得到的所有可达状态得到下一个可达状态。

就比如初始的时候可达状态一定是00000....1,因为当i == 0的时候一定可达。那如果第一个reward是3,那么首先考虑条件i >= reward && i < 2 * reward。

这里呢比较难想,在转换到二进制表示状态之后如何判断条件呢?

其实我们只需要看他是否会越界即可,怎么理解呢就比如我当前状态是00111表是0、1、2可达,那么如果当前reward = 3,我们把当前状态左移size = 5 - 3位在移回来,就变成了00011这样的话就已经去掉了状态3,因为状态3加2之后达到了5违反了:rewardValues[i] 大于 你当前的总奖励 x

这样的话呢就很清楚了,在条件判断完之后将当前状态左移reward位然后于原状态|一下即可

(位运算的相关介绍位运算(&、^、补码、lowbit操作)-CSDN博客)

就得到了dp[i] = dp[i] | dp[i - reward]

代码

class Solution {
public:
    int maxTotalReward(vector<int>& rewardValues) {
        int n = rewardValues.size();
        if(n == 1) return rewardValues[0];

        sort(rewardValues.begin(),rewardValues.end());
        rewardValues.erase(unique(rewardValues.begin(),rewardValues.end()),rewardValues.end());

        bitset<100000> f{1};
        for(int i = 0;i < n;i ++){
            int v = rewardValues[i];
            int d = f.size() - v;
            f |= f << d >> d << v;
        }

        for(int i = rewardValues[n - 1] * 2 - 1;i >= 0;i --){
            if(f.test(i)) return i;
        }

        return 0;
    }
};

加油

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

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

相关文章

数字IC后端实现 | Innovus各个阶段常用命令汇总

应各位读者要求&#xff0c;小编最近按照Innovus流程顺序整理出数字IC后端项目中常用的命令汇总。限于篇幅&#xff0c;这次只更新到powerplan阶段。有了这份Innovus常用命令汇总&#xff0c;学习数字IC后端从此不再迷路&#xff01;如果大家觉得这个专题还不错&#xff0c;想继…

Linux 字符设备驱动 之 无法归类的《杂项设备驱动》

学习目标&#xff1a; 了解 杂项设备驱动 和普通字符设备的异同&#xff0c;及杂项设备驱动程序的写法 学习内容&#xff1a; 一、杂项设备驱动的特别之处 杂项设备&#xff08;Miscellaneous Devices&#xff09;是一种通用的设备类型&#xff0c;用于表示那些不适合其他设备…

LeetCode 热题 100之普通数组

1.最大子数组和 思路分析&#xff1a;这个问题可以通过动态规划来解决&#xff0c;我们可以使用Kadane’s Algorithm&#xff08;卡登算法&#xff09;来找到具有最大和的连续子数组。 Kadane’s Algorithm 的核心思想是利用一个变量存储当前的累加和 currentSum&#xff0c;并…

Prometheus自定义PostgreSQL监控指标

本文我们将介绍如何在Prometheus中创建自定义PostgreSQL指标。默认情况下由postgres_export运行的查询可能不能满足用户需求&#xff0c;但我们可以创建自定义查询&#xff0c;并要求postgres_exporter公开自定义查询的结果。postgres_exporter最近被移到了Prometheus Communit…

acwing排列数字

排列数字 给定一个整数 n&#xff0c;将数字 1∼n排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 n。 输出格式 按字典序输出所有排列方案&#xff0c;每个方案占一行。 数…

lvs知识点归纳

LVS&#xff08;Linux Virtual Server&#xff09;是 Linux 内核的一种负载均衡技术&#xff0c;主要用于实现高可用性和高性能的服务器集群。以下是一些关键知识点的归纳&#xff1a; 基本概念 虚拟服务器&#xff1a;将多台物理服务器&#xff08;真实服务器&#xff09;抽象…

论文速读 - Cleaner Pretraining Corpus Curation with Neural Web Scraping

这是论文 Cleaner Pretraining Corpus Curation with Neural Web Scraping 的速读笔记&#xff0c;同时简要分析这篇论文作者的实现代码. 论文的主要工作是提出了基于神经网络的高效crawler. 这里先澄清scraper和crawler的区别&#xff0c;一图胜千言. Abstract The web conta…

openpnp - bug - 散料飞达至少定义2个物料

文章目录 openpnp - bug - 散料飞达至少定义2个物料笔记END openpnp - bug - 散料飞达至少定义2个物料 笔记 散料飞达上定义的物料个数用完了&#xff0c;现在只需要一个料就可以。 用顶部相机去找编带上是否还有一个单独的料&#xff0c;找到了。 定义散料飞达的料为1个&…

springboot使用attachment方式下载文件损坏问题解决

文章目录 场景解决方式全部代码 场景 之前使用springboot下载文件一直正常&#xff0c;今天新对接一个接口出现文件破损&#xff0c;无法下载。 之前的代码: Overridepublic ResponseEntity<ByteArrayResource> resultExcel(ExcelResultDTO excelResultDTO) {log.info(…

CentOS7系统内核升级

1. 安装新内核 采用离线方式升级 去到下面网站中下载rpm安装包 https://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/下载 wget https://mirrors.coreix.net/elrepo-archive-archive/kernel/el7/x86_64/RPMS/kernel-lt-5.4.278-1.el7.elrepo.x86_64…

探寻闲鱼libsgmain加解密算法(4) ——JNI入口跳转

关注我的人都知道我一直在学习阿里的加密和算法&#xff0c;除了研究逆向问题&#xff0c;还会把学来的阿里技术用在自己的应用上。 为什么&#xff1f;因为学习大厂的应用&#xff0c;是进步最快的方法。而大厂在安全和加密方面的技术&#xff0c;个人觉得阿里做的是最好的。 …

Maven项目管理工具-初始+环境配置

1. Maven的概念 1.1. 什么是Maven Maven是跨平台的项目管理工具。主要服务于基于Java平台的项目构建&#xff0c;依赖管理和项目信息管理。 理想的项目构建&#xff1a;高度自动化&#xff0c;跨平台&#xff0c;可重用的组件&#xff0c;标准化的流程 maven能够自动下载依…

Maven 不同环境灵活构建

需求: 使用 Maven根据不同的构建环境&#xff08;如开发、测试、生产&#xff09;来定义不同的配置&#xff0c;实现灵活的构建管理。 需要Demo项目的可以参考&#xff1a;我的demo项目 一、项目分层 一般的初创项目不会有特别多的配置文件&#xff0c;所以使用 spring.profile…

Android调用系统相机录像并设置参数

最近要做一个 Android上的录像功能&#xff0c;由于之前做拍照功能完全是用自定义方式&#xff0c;太麻烦。故这次决定直接调用系统相机来录像。 一、添加权限 首先&#xff0c;添加必要的权限 <!-- 授予该程序使用摄像头的权限 --><uses-permission android:name&q…

K8s中TSL证书如何续期

TSL是什么 K8s中的作用是什么&#xff1f; 在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;TSL 指的是 Transport Layer Security&#xff0c;也就是传输层安全协议。它是用来保护在网络上传输的数据的安全性和隐私性。 TSL 在 Kubernetes 中的作用包括&#xff1a;…

B+树(B树的改进)

目录 一、什么是B树&#xff1f; 二、B树的性质 1.B树被广泛作为数据库索引的索引结构 2.m个分支的结点有m个元素 3.每个元素对应子结点最大值 4.多级索引结构 5.叶子结点层包含所有元素 三、B树和B树的区别 四、B树的查找 1.顺序查找 2.随机查找 3.范围查找 一、什…

JVM机制

文章目录 JVM 简介JVM内存划分堆&#xff08;线程共享&#xff09;Java虚拟机栈&#xff08;线程私有&#xff09;本地方法栈&#xff08;线程私有&#xff09;程序计数器&#xff08;线程私有&#xff09;方法区&#xff08;线程共享&#xff09; JVM类加载机制类加载过程双亲…

校园表白墙源码修复版

此校园表白墙源码基于thinkphp&#xff0c;因为时代久远有不少bug&#xff0c;经本人修复已去除大部分bug&#xff0c;添加了美化元素。 https://pan.quark.cn/s/1f9b3564c84b https://pan.baidu.com/s/1bb9vu9VV2jJoo9-GF6W3xw?pwd7293 https://caiyun.139.com/m/i?2hoTc…

群控系统服务端开发模式-应用开发-业务架构逻辑开发准备工作

安装与仓库已经调整完毕&#xff0c;现在开发业务架构逻辑&#xff0c;其次再开发功能逻辑。业务架构逻辑开发与功能逻辑开发不是一回事&#xff0c;一定要明白。业务架构指的是做某一件事或是某一种类型的事的逻辑&#xff0c;在互联网web应用中通常指一套系统的外在逻辑&…

js 的宏任务和微任务

宏任务 (macro-task) 与微任务 (micro-task) 在 JavaScript 中&#xff0c;宏任务&#xff08;macro-task&#xff09;和微任务&#xff08;micro-task&#xff09;是任务队列&#xff08;task queue&#xff09;中两个不同的任务类型&#xff0c;它们是 JavaScript 异步编程机…