leetcode 879. Profitable Schemes(有利润的计划)

news2024/11/15 11:45:39

在这里插入图片描述
有几个工程,每个工程需要group[ i ]个人去做,做完了可以得到profit[ i ]的利润。
现有2个限制条件:
人数上限是n, 且参加了一个工程的人不能再参加其他工程。
利润下限minProfit, 至少要获得minProfit的利润。
问有多少种工程的选法,可以满足在<=n个人时,能达到>=minProfit的利润。

思路:

1.三维DP

整体有点复杂,从简单的例子入手,
拿Example1来说,
dp[i][j][k] 代表前 i个工程,选 j 个人参加, 最小利润是 k
这里i从1开始,所以i>=1 && i <= group.length, 0 <= j <= n, 0 <= k <= minProfit(k越小,可选的工程越多)

如果只是一个限制条件,那么二维DP,现在有2个限制条件,先看三维DP,后面再简化到二维。

初始条件,0个工程,0个人,最小利润是0,这种情况有一种scheme, 就是什么都不干(不干也是一种方法)。
所以 dp[0][0][0] = 1.

i= 1, j = 0, k = 0, 即1个工程,限制人数不能超过0个人,下限利润为0,
人数限制在0个,谁都不能干,所以干不了,可选的方法数和dp[0][0][0]一样。
dp[1][0][0] = dp[0][0][0] = 1
不管再来几个工程,也还是干不了,dp[i][0][k] = dp[i-1][0][0]
如果还是0个人,把利润k 抬高,直到minProfit, 都干不了,还保持在dp[0][0][0]
即 dp[i][0][k] = dp[i-1][0][0]

所以只要group[i]的人数 > j (超过人数限制),这个工程就干不了,只能选择不干,状态保持在上一个工程
dp[i][j][k] = dp[i-1][j][k]

上面j =0, 1都是这个情况,
现在把人数上限增加到2, 即 j = 2,
第1个工程,需要人数group[i-1], 能赚到profit[i-1], (ℹ是第几个工程,从1开始)
现在group[0] = 2 <= j, 能干,
利润下限为k ,
如果接了这个工程后利润下限为k, 那么到上一工程为止利润下限为max(0, k - profit[i-1])
接了该工程后人数上限为 j, 那么在接这个工程前人数上限为j - group[i-1],
所以如果接这个工程,上一状态就应该是dp [ i-1 ] [ j-groups[i-1] ] [ max(0, k - profit[i-1]) ]

当然也可以选择不干这个工程,那么就是两种情况,干与不干。

所以在 group[i-1] < j时(人数没超过上限)
dp[i][j][k] = dp[i-1][j][k] + dp[i-1][j-groups[i-1]][max(0, k - profit[i-1])] (可干可不干两种情况)

最后的结果是当最后一个工程为止,选 0 ~ n 个人参与时,下限利润为minProfit的schme之和。
也就是对 j = 0~n的情况求和,dp [ group.length ] [ j ] [ minProfit ]

    public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
        int len = group.length;
        int[][][] dp = new int[len+1][n+1][minProfit+1];
        dp[0][0][0] = 1;
        int sum = 0;
        int mod = (int)1e9+7;
        //dp[i][j][k]:j个worker被选到前i个crime中,下限profir是k
        //最后需要的结果:sum_{j}(dp[len][j][minProfit]),也就是说可以选1~n个人来做,
        //前len个crime,下限profit是minProfit

        for(int i = 1; i <= len; i++) { //前n个crime  
            int members = group[i-1];
            int money = profit[i-1];          
            for(int j = 0; j <= n; j++) {  //选j个人参与     
                for(int k = 0; k <= minProfit; k++) {
                    if(members > j)//group[j]的人不能干第i个crime(超过人数了),方式不会增多
                        dp[i][j][k] = dp[i-1][j][k] % mod;
                    //group[i]的人要干第i个crime,那么其他的j-group[i]的人就干前i-1个crime
                    else   //group[i]能干第i个crime,在原有方式数的基础上增加新的ways,该crime可参与可不参与
                        dp[i][j][k] = (dp[i-1][j][k] + dp[i-1][j-members][Math.max(0, k-money)])%mod;
                }
            }
        }

        //挑选1~n个人来做前len个crime,下限是minProfit
        for(int i = 0; i <= n; i++)
            sum = (sum + dp[len][i][minProfit]) % mod;
        return sum;
    }

2.二维DP

前面三维DP中可以看到dp[i] [… ] [… ] 只与dp[i-1] […] […]有关
所以考虑去掉 i 这一维,直接在二维dp上更新,

可以看到在group [ i ] > j 时 dp [ i ] […] […]是维持在dp[i-1] […] […]不变的,
所以这种情况下不需要更新二维DP,只需考虑 group [ i ] <= j 的情况,
因此限制 j 在 group[i] ~ n 范围。

需要注意的是这种情况下, j, k 必须是降序递减。
具体原因写在注释里面。

    public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
        int len = group.length;
        int[][] dp = new int[n+1][minProfit+1];
        dp[0][0] = 1;
        int sum = 0;
        int mod = (int)1e9+7;
        //dp[i][j][k]:j个worker被选到前i个crime中,下限profit是k
        //最后需要的结果:sum_{j}(dp[len][j][minProfit]),也就是说可以选1~n个人来做,
        //前len个crime,下限profit是minProfit

        for(int i = 1; i <= len; i++) { //前n个crime  
            int members = group[i-1];
            int money = profit[i-1];          
            for(int j = n; j >= members; j--) {  //选j个人参与     
                for(int k = minProfit; k >= 0; k--) {
                    //j < members时: 维持在dp[i-1]这个维度的值,不需要更新
                    
                    //现在只考虑j>=members的情况:
                    //如果想去掉i维度,原则是一旦dp[j][k]被更新,后面不能再用第二次,
                    //因为用第二次相当于dp[i-1][j][k]已经变了,不是原来的值了

                    //如果j,k是从小到大递增,那么一旦dp[j][k]被更新(相当于dp[i-1][j][k]被更新了)
                    //而后面j增大,j-members还有可能得到原来更新过的较小的j,会影响结果
                    //而j,k从大到小,先更新的是较大的j,k处,一旦更新一次,后面不会再用到
                    //因为j-members,k-money只会更小,不会得到原来较大的值
                    //dp[i][j][k] = (dp[i-1][j][k] + dp[i-1][j-members][Math.max(0, k-money)])%mod;
                    dp[j][k] = (dp[j][k] + dp[j-members][Math.max(0, k-money)]) % mod;
                }
            }
        }

        //挑选1~n个人来做前len个crime,下限是minProfit
        for(int i = 0; i <= n; i++)
            sum = (sum + dp[i][minProfit]) % mod;
        return sum;
    }

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

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

相关文章

Zuul源码解析(一)

说在前面 我们公司有一个线上服务报错通知群&#xff0c;经常报网关服务的一个 EOFException 异常。这个异常报出来好久了&#xff0c;如下图所示&#xff0c;艾特相关的人也不去处理&#xff0c;大概是不重要异常吧&#xff0c;反正看样子是不影响线上核心业务流程。 然后我上…

FreeRTOS学习笔记(一)——初识FreeRTOS

FreeRTOS官网&#xff1a;FreeRTOS - 适用于具有物联网扩展功能的嵌入式系统的市场领先 RTOS&#xff08;实时操作系统&#xff09; FreeRTOS源码下载&#xff1a;FreeRTOS Real Time Kernel (RTOS) - Browse /FreeRTOS at SourceForge.net 目录 0x01 FreeRTOS编程风格 一…

用CentOS服务器自己搭建部署个Discuz论坛网站,网站搭建教程

Linux系统CentOS服务器使用堡塔搭建论坛网站全套教程。服务器大本营&#xff0c;技术文章内容集合站发车啦&#xff01; 操作系统&#xff1a;Centos 7.6 网站程序&#xff1a;Discuz-X3.4 前言 首先&#xff0c;搭建一个网站需要准备&#xff1a;服务器、域名、网站程序。 …

PWM控制直流电机

一&#xff0c;TB6612电机驱动模块 直流电机属于大功率器件&#xff0c;GPIO无法直接驱动&#xff0c;需要电机驱动模块配合&#xff0c;才能驱动直流电机. TB6612可以驱动2个直流电机。由IN1&#xff0c;IN2控制电机旋转方向&#xff0c;由PWM控制电机旋转速度。 二&#xf…

基于Oracle VM VirtualBox的ubuntu的安装

基于Oracle VM VirtualBox的ubuntu的安装 感谢詹老师的帮助使我得以完成本次安装&#xff0c;以下为本次安装的一个小小的记录。 目录 基于Oracle VM VirtualBox的ubuntu的安装Oracle VM VirtualBox的下载与安装ubuntu的下载Oracle VM VirtualBox下安装ubuntu安装 ROS Melodi…

GitHub 开源神器 Bark模型,让文本转语音更简单

今天跟大家分享一个文本转语音的开源模型&#xff1a;Bark Bark 是由Suno创建的基于转换器的文本到音频模型。Bark 可以生成高度逼真的多语言语音以及其他音频 - 包括音乐、背景噪音和简单的音效。该模型还可以产生非语言交流&#xff0c;如大笑、叹息和哭泣。 该项目刚开源不…

二叉树OJ题(C++实现)

文章目录 1.二叉树创建字符串2. 二叉树的最近公共祖先3.二叉搜索树与双向链表4.从前序与中序遍历序列构造二叉树 1.二叉树创建字符串 二叉树的层序遍历 OJ连接 主要思路是借助一个队列&#xff0c;将每一层的数据以size统计&#xff0c;当size为0时说明该层数据已经输入完&…

Unity Physics2D 2d物理引擎游戏 笔记

2d 材质 里面可以设置 摩擦力 和 弹力 Simulated&#xff1a;是否在当前的物理环境中模拟&#xff0c;取消勾选该框类似于Disable Rigidbody&#xff0c;但使用这个参数更加高效&#xff0c;因为Disable会销毁内部产生的GameObject&#xff0c;而取消勾选Simulated只是禁用。…

详解C语言string.h中常用的14个库函数(四)

本篇博客会讲解最后4个函数&#xff0c;分别是memset, memcpy, memmove, memcmp。这4个函数开头都是mem&#xff0c;即memory&#xff08;内存&#xff09;的缩写。 memset void * memset ( void * ptr, int value, size_t num );memset可以用来设置内存中的值。该函数可以把从…

深度学习实战——循环神经网络(RNN、LSTM、GRU)

忆如完整项目/代码详见github&#xff1a;https://github.com/yiru1225&#xff08;转载标明出处 勿白嫖 star for projects thanks&#xff09; 目录 系列文章目录 一、实验综述 1.实验工具及内容 2.实验数据 3.实验目标 4.实验步骤 二、循环神经网络综述 1.循环神经…

【数据结构】第五章 树与二叉树

文章目录 知识体系5.1 树的基本概念5.1.1 树的定义5.1.2 基本术语5.1.3 树的性质 5.2 二叉树的概念5.2.1 二叉树的定义和主要特性5.2.2 二叉树的存储结构 5.3 二叉树的遍历和线索二叉树5.3.1 二叉树的遍历5.3.2 线索二叉树 5.4 树、森林5.4.1 树的存储结构5.4.2 树、森林与二叉…

uniapp踩坑之项目:各端条件编译

在 HBuilderX 中&#xff0c;ctrlalt/ 即可生成正确注释&#xff08;js&#xff1a;// 注释、css&#xff1a;/* 注释 */、vue/nvue模板&#xff1a; &#xff09;。 #ifdef&#xff1a;if defined 仅在某平台存在#ifndef&#xff1a;if not defined 除了某平台均存在%PLATFORM…

ARM busybox 的移植实战2

一、busybox 源码分析1 1、源码目录梳理 2、整个程序入口的确认 (1) 分析一个程序&#xff0c;不管多庞大还是小&#xff0c;最好的路线都是 按照程序运行时的逻辑顺序来。所以找到一个程序的入口至关重要。 (2) 学 C 语言的时候都知道&#xff0c;程序的主函数 main 函数就是…

机器学习算法 随机森林

文章目录 一、概述1.1 集成学习1.2 决策树1.3 随机森林 二、Sklearn中的随机森林2.1 分类树API2.2 参数 2.2 回归树API2.2.1 重要参数 2.3 随机森林调参 三、总结 一、概述 1.1 集成学习 多个模型集成成为的模型叫做集成评估器&#xff08;ensemble estimator&#xff09;&am…

车载软件架构——闲聊几句AUTOSAR BSW(二)

我是穿拖鞋的汉子,魔都中坚持长期主义的工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 我特别喜欢一个老话,来都来了。我觉得这就是松弛感,既然来了,就开心起来吧!松弛感来自于专注,焦虑不是靠克服的,是靠忘记的,当你很专注做一件事的时候…

HNCTF-re部分复现

目录 [HNCTF 2022 WEEK3]Help_Me! [HNCTF 2022 WEEK3]Whats 1n DLL? [HNCTF 2022 WEEK4]ez_maze 这几天在做HNCTF的week3&#xff0c;week4部分&#xff0c;学到了一些不知道的没接触过的东西&#xff0c;所以记录一下 [HNCTF 2022 WEEK3]Help_Me! 题目下载&#xff1a;下…

onnx笔记2:onnx操作实例

1. 介绍 本文以yolov5s模型,演示对yolov5s.onnx模型文件的读取,修改等操作 2. onnx操作 2.1 获取数据 (1) 案例1 :读取weights数据 比如获取yolov5s.onnx第一个Conv的weights数据。 点击左侧第一个Conv, 右侧INPUTS下面的W点开+号,可以看到该Conv的weight的name为m…

MySQL --- 主从复制、读写分离

一、MySQL主从复制 MySQL数据库默认是支持主从复制的&#xff0c;不需要借助于其他的技术&#xff0c;我们只需要在数据库中简单的配置即可。接下来&#xff0c;我们就从以下的几个方面&#xff0c;来介绍一下主从复制 1.1、介绍 MySQL主从复制是一个异步的复制过程&#xff0c…

linux 安装 oracle 11g

linux 安装 oracle 11g 1、下载oracle 11g (11.2.0.1.0)1.1、Oracle Database 11.2.0.1.01.2、Oracle Database Grid Infrastructure 11.2.0.1.01.3、客户端 2、安装文档3、安装前准备3.1、建立用户和用户组3.2、sysctl3.3、security limits3.4、其他设置3.5、创建安装目录3.6、…

SpringBootWeb请求响应

目录 前言 1. 请求 1.1 Postman 1.1.1 介绍 1.1.2 安装 1.2 简单参数 1.2.1 原始方式 1.2.2 SpringBoot方式 1.2.3 参数名不一致 小结 1.3 实体参数 1.3.1 简单实体对象 1.3.2 复杂实体对象 1.4 数组集合参数 1.4.1 数组 1.4.2 集合 1.5 日期参数 1.6 JSON参…