首页 > 编程语言 >算法题——执行操作可获得的最大总奖励

算法题——执行操作可获得的最大总奖励

时间:2024-10-25 17:58:39浏览次数:7  
标签:std 下标 选择 奖励 算法 rewardValues 执行 dp

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

题干

给你一个整数数组 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 * 104
1 <= rewardValues[i] <= 5 * 104

思路

首先,题目要求选择的rewardValues[i]>x,那么先选较大的值就无法再选择较小的值,因此应该先选较小的值再选较大的值,开始前先对rewardValue进行排序。

另外,对于两个数a1 == a2,如果选择了a1,那么x+a1>a2(或者a1 == a2),a2就不可能再被选择,也即不可能选择两个值相同的数,因此可以对数组进行去重。

记max(rewardValues) = m,本题可以得到的最大总奖励最多为 2 * m-1。将问题化为子问题进行分析:考虑对于一个数y,如果要选择数y,那么一定有当前的总奖励x < y,即x最大可能为y-1,假设y的下标为i,该情况可以描述为选择前i个数的最大总奖励的最大可能值为 2 * y-1。因此,对于整个数组,可以得到的最大总奖励最多为 2 * m-1

排序后,本题可以描述为0-1背包问题,dp[i][j]表示前i个数可以取得的最大总奖励j,对于第i个数,只有选或者不选两种情况。

  • 选,需满足 j - rewardValues[i] < rewardValues[i] 和 j - rewardValues[i] >= 0,即 rewardValues[i] <= j < 2*rewardValues[i],dp[i][j] = dp[i-1][j-rewardValues[i]]。
  • 不选,dp[i][j] = dp[i-1][j]。

因此 dp[i][j] = dp[i-1][j] || dp[i-1][j-rewardValues[i]],最终结果为dp[n][j]。

但是本题的数据量较大,需要去掉第一重维度,那么就变成dp[j] = dp[j] | dp[j-rewardValues[i]],再使用bitset优化,将一维的数组转为二进制数,二进制位第j位 f[j] = 1表示可以取到j这个值,f[j] = 0表示无法取到j这个值,也可以用true和false来表示是否可以取到该值。考虑数组A={2,3,4}的求解过程。

用一个bitset数组f来表示是否可以得到某一个值(实际上f是一个二进制数,这里带下标只是为了解释原理),f[i]表示前i个数能得到的值,如果该最大奖励值能由不多于i个数取到,则fi为true,f的大小为 2 * m-1。以二进制的方式表示,其中选择0个数时f = 10000000,选择第一个数时f = 10100000,选择前两个数时f = 10110100,表示可以得到2、3、5,选择前三个数时f=10111111,表示可以得到2、3、4、5、6、7。

分析f3,可以看出,取rewardValues[i] = 4时,需要考虑f[0]、f[1]、f[2]和f[3],也即,如果f[0]、f[1]、f[2]和f[3]为1,那么f[0]、f[1]、f[2]和f[3]加上4就可以得到f[4]、f[5]、f[6]和f[7]为1。记rewardValues[i]为v,相当于取f的低v位,向高位移动v位,再与高位进行or运算,得到是否能取到高位对应的v个值(上图中左侧实际上对应bitset数组的低位)。实际上遍历rewardValues进行对f的更新的过程就是考虑选择或者不选择某个值v时可以得到的最大奖励值。

eg:选择前一个数时f=00000101,选择前两个数时,可选择的数是3,将f的低三位左移len-3位,再右移len-6位,得到00101000,与f=00000101进行或运算,得到f=00101101。

代码:

int maxTotalReward(std::vector<int> &rewardValues)
{
    //该部分优化为:记一下rewardValues的最大值m,如果有一个数等于m-1或者有两个数相加等于m-1,那么结果一定为2*m-1
    int m = std::ranges::max(rewardValues);
    std::unordered_set<int> us;
    for (auto &i : rewardValues)
    {
        if (us.contains(i))
        {
            continue;
        }
        if (i == m - 1 || us.contains(m - 1 - i))
        {
            return 2 * m - 1;
        }
        us.insert(i);
    }
    //该部分对rewardValues进行排序,并去重
    std::ranges::sort(rewardValues);
    rewardValues.erase(std::unique(rewardValues.begin(), rewardValues.end()), rewardValues.end());
    std::bitset<100000> f{1};
    //记f.size()=len,f先左移f-i位,把低i位全部移到最高位,其余低位为0
    //然后右移len-i-i位,相当于把原来的低i位,向左移动了i位,其余位全部置0,即得到一个类似00000xxxx0000的二进制数
    for (auto &i : rewardValues)
    {
        f |= f << (f.size() - i) >> (f.size() - i * 2);
    }
    //从最大的可能值开始向前查询是否存在结果
    for (int i = rewardValues.back() * 2 - 1; ; --i)
    {
        if (f.test(i))
        {
            return i;
        }
    }
}

优化前复杂度为 5 * 104 * 2 * 5 * 104 = 5 * 109,优化后复杂度为 5 * 109/ w,w为表示数组bitset需要的二进制位数,一般为64或32。

标签:std,下标,选择,奖励,算法,rewardValues,执行,dp
From: https://www.cnblogs.com/HD0117/p/18503054

相关文章

  • 全面了解 NGINX 的负载均衡算法
    NGINX提供多种负载均衡方法,以应对不同的流量分发需求。常用的算法包括:最少连接、最短时间、通用哈希、随机算法和IP哈希。这些负载均衡算法都通过独立指令来定义,每种算法都有其独特的应用场景。以下负载均衡方法(IP哈希除外)适用于HTTP、TCP和UDP上游池:轮询轮询(Ro......
  • K-近邻算法(KNN)
    """K-近邻算法用于分类和回归问题。比如,判断一款游戏是否受欢迎。KNN算法的基本思想是:如果一个样本在特征空间中的k个最邻近的样本中的大多数属于某个类别,则该样本也属于这个类别。KNN算法的实现方法有两种:1.基于欧氏距离的KNN算法2.基于余弦相似度的KNN算法KNN算法的优点:1.简......
  • 算法设计实验6
    p1249有一个8*8的棋盘,行号、列号均为0-7,一个特殊放个的位置是(5,6),给出采用L形骨牌覆盖其他全部方格的一种方案1#include<ostream>2#include<iostream>3#defineMAX_SIZE84usingnamespacestd;5intk;6intx,y;7intboard[MAX_SIZE][MAX_SIZE];8int......
  • 【数据结构和算法】一、算法复杂度:时间复杂度和空间复杂度)
    目录1、算法复杂度1.1概念1.2评价指标1.3时间复杂度1.3.1什么是时间复杂度1.3.2常数阶O(1)1.3.3  线性阶O(n)1.3.4 对数阶O(logN)1.3.5  线性对数阶O(nlogN)1.3.6 平方阶O(n²)1.3.7  立方阶O(n³)、K次方阶O(n^k)1.4 空间复杂度1.4.1 空间复......
  • 数据结构图的最短路径-弗洛伊德算法(有向图+数据结构课本C++代码一比一转C语言+邻接矩
    弗洛伊德算法有向图代码如下:#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<stdlib.h>#include<limits.h>#defineMaxInt32767#defineMVNum100intPath[MVNum][MVNum];//存放前驱索引的intD[MVNum][MVNum];//存放当前已知的权值//图的邻接......
  • 非常牛 H 开头的算法
    考前发现欧拉回路不会。然后寻求多方大佬,最后比较深刻地理解了一个叫Hierholzer的算法。这个算法暴力写法是:先找一条欧拉路径,然后把这个路径上的点删了。再看看这个链上的点能不能再被换成环,能的话就把这个点换成新找的路径,这步用链表插入,这个过程是递归的。复杂度很......
  • 数学算法
    1.筛质数力扣相关题目:204.计数质数、2523.范围内最接近的两个质数要在某个范围内计算出所有质数时,先在这个范围内做预处理,把所有的质数筛出来埃氏筛:从前往后,把质数的倍数都去掉(因为这肯定不是质数了)constintMX=5e6; //比如数据范围是0~5*10^6vector<int>primes; //......
  • 【有啥问啥】视频插帧算法技术原理详解
    视频插帧算法技术原理详解引言视频插帧(VideoInterpolation)技术,作为计算机视觉领域的一项重要应用,旨在通过算法手段在已有的视频帧之间插入额外的帧,从而提升视频的帧率,使其看起来更加流畅。这一技术不仅广泛应用于电影特效、视频游戏、运动捕捉等领域,还随着计算机视觉和......
  • 越界检测视频分析网关区域入侵识别人员入侵算法的技术原理和视频监控应用
    在传统的监控模式下,依赖人工持续监视视频画面存在明显的局限性,包括疲劳、注意力分散以及无法覆盖所有区域等问题,这使得实现24小时、全方位监控变得困难。而人工智能技术的应用,通过在关键位置部署摄像头,能够捕获连续的视频流。结合深度学习模型,这些视频流可以被实时分析,从而提高了......
  • 【优选算法】——滑动窗口(下篇)
    目录1、水果成篮2、找到字符串中所有字母异位词3、串联所有单词的子串4、最小覆盖子串1、水果成篮你正在探访一家农场,农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示,其中 fruits[i] 是第 i 棵树上的水果 种类 。你想要尽可能多地收集水果......