当前位置: 首页 > news >正文

暴力递归转动态规划(九)

题目
题有点难,但还挺有趣
有一个咖啡机数组arr[],其中arr[i]代表每一个咖啡机冲泡咖啡所需的时间,有整数N,代表着准备冲咖啡的N个人(假设这个人拿到咖啡后喝完的时间为0,拿手里咖啡杯即变空),有一台洗咖啡杯的机器,一次只能洗一只杯子,每次洗咖啡杯消耗的时间为a,如果咖啡杯自己挥发变干净,消耗的时间是b,返回从排队开始到所有咖啡杯变干净的最短时间。

分析:

  1. 根据题意梳理后可得知,每台咖啡机冲泡咖啡是并行操作的,但是单独的咖啡机自己,是只有等当前的咖啡冲泡完成后,才可冲泡下一杯,是串行操作的。
  2. 洗咖啡杯的机器消耗时间为a,但是要等咖啡冲泡完成后,才可进行清洗。举例:1号咖啡机冲泡1杯咖啡时间为2分钟,从0时间点开始冲泡一杯咖啡,2分钟时间点结束。那么洗咖啡杯的机器是在2分钟的时间点开始工作,在2 + a时间点工作完成,才可进行下一只咖啡杯的清洗。需要注意的是:如果咖啡杯1和2都选择清洗,但是1号咖啡杯是9时间点喝完,2号咖啡杯是6时间点喝完,则2号咖啡杯在清洗时,开始的时间点是 9 + a,是根据上一直需要清洗的咖啡杯的时间来决定的。
  3. 咖啡杯自己挥发是并行操作,并且变干净的时间都是b。

暴力递归
依然是从暴力递归开始分析,并从暴力递归转换成动态规划,但是在暴力递归之前,先将这道题拆解成2道题来看。
首先是根据咖啡机数组arr和准备冲咖啡的人数N来实现一个模拟排队的功能。作用是能够获取到每个人能够最快获取到咖啡的时间点

模拟排队
模拟排队的功能实现用到了PriorityQueue,并且自己实现了咖啡机的比较规则,根据PriorityQueue的特性让效率最快的咖啡机始终在最上面并进行使用。其中(0,1)表示当前咖啡机可用时间点为0,冲泡一杯咖啡时间为1。
在这里插入图片描述

解释一下上边的图:
咖啡机数组arr{1,3,7}代表着0号咖啡机冲泡一杯咖啡所需时间为1,1号咖啡机所需时间为3,2号咖啡机所需时间为7。开始时咖啡可用时间都从0时间点开始。一共有5个人排队冲咖啡。
根据咖啡机冲泡一杯所需时间 和 咖啡机下一次可用时间 来实现咖啡机的效率最大化

所以:

  1. 第一个人过来时,会去0号咖啡机冲咖啡,此时咖啡机在1时间点冲完,并且咖啡机下次可用时间点为1。
  2. 第二个人过来时,0号咖啡机可用时间点为1,冲泡一杯咖啡所需时间为1, 1 + 1 = 2 ,小于1号咖啡机冲泡一杯的时间3,所以还是会选择0号咖啡机冲泡咖啡。
  3. 第三个人过来时,0号咖啡机会在2时间点可用,冲泡一杯咖啡时间依然是1,但是此时1号咖啡机可用时间点是0,冲泡咖啡的时间是3。此时0号咖啡机和1号咖啡机冲泡一杯咖啡结束的时间点相同(用谁都可以),我们假设用1号咖啡机,用完后,1号咖啡机可用时间点为3,**根据PriorityQueue的特性,0号咖啡机又会排到上面 **。
  4. 所以第四个人、第五个人过来都会选择0号咖啡机。

代码

public static class Machine {// 咖啡机可以工作的时间点int timePoint;//泡一杯咖啡所需时间int workTime;public Machine(int timePoint, int workTime) {this.timePoint = timePoint;this.workTime = workTime;}}//自定义比较器public static class MachineComparator implements Comparator<Machine> {@Overridepublic int compare(Machine o1, Machine o2) {return (o1.timePoint + o1.workTime) - (o2.timePoint + o2.hashCode());}}public static int forceMake(int[] arr, int N, int a, int b) {PriorityQueue<Machine> heap = new PriorityQueue<>(new MachineComparator());//初始化时,填充heapfor (int i = 0; i < arr.length; i++) {heap.add(new Machine(0, arr[i]));}//每个人最快可以喝到咖啡的数组int[] drinks = new int[N];for (int i = 0; i < N; i++) {//获取堆顶的咖啡机元素Machine curMachine = heap.poll();//咖啡机下次可用时间curMachine.timePoint += curMachine.workTime;//什么时间可以喝到咖啡drinks[i] = curMachine.timePoint;//再次压入堆中heap.add(curMachine);}//process方法是递归方法,求出咖啡杯变干净的最少时间。return process(drinks, a, b, 0, 0);}

第一个模拟排队的问题解决了,接下来就是正式的暴力递归。
暴力递归方法返回drinks[index…]位置变干净的最小时间。
所以此时base case也可以确定下来了 index == drinks.length。 而每只杯子可以选择清洗,也可以选择挥发变干净。
所以在递归向下传递时需要注意清洗咖啡杯机器的可用时间的变化。

代码
代码中在向下传递时,如果我选择了清洗,则机器的可用时间是会向后延长的,如果选择了风干,也是要根据咖啡杯的可用时间来取最大值的(木桶原理),最后,在清洗和风干中,取小的。

 	//drinks: 每个人喝到咖啡的最短时间//wash :  用洗咖啡杯机器洗一只咖啡杯的时间// air :  空气挥发一杯咖啡杯的时间//index:  第几只杯子//free : 下一次洗咖啡杯机器可用时间public static int process(int[] drink, int wash, int air, int index, int free) {//没有杯子了if (index == drink.length) {return 0;}//选择洗int selfClean1 = Math.max(drink[index], free) + wash;//向下传递,下一只杯子清洗干净的时间,此时清洗咖啡杯机器的可用时间为selfClean1int restClean1 = process(drink, wash, air, index + 1, selfClean1);//木桶原理,因为选择了清洗,所以要看当前杯子selfClean和下一个杯子restClean那个时间更大,选择哪个int p1 = Math.max(selfClean1, restClean1);// 选择风干int selfClean2 = drink[index] + air;//free依然是free,清洗咖啡杯机器的时间没有变化。int restClean2 = process(drink, wash, air, index + 1, free);//同理int p2 = Math.max(selfClean2, restClean2);//在风干和清洗中选择一个最小的。return Math.min(p1, p2);}

动态规划
根据暴力递归中的代码来改写动态规划,从暴力递归代码中可以看出,可变参数是数组下标index和清洗咖啡杯机器的freeTime。并且index的范围是 0 ~ drinks.length,需要注意的是freeTime,和之前题的可变参数范围不同。这道题中freeTime的时间范围并不好确定,需要根据具体的业务来算出来(按照drinks中最大喝完咖啡的时间 + 清洗一杯咖啡杯的时间)
所以dp[][] 初始化时,可以确定范围 dp[N + 1][maxFree]。
还需要注意的一点是,因为在遍历dp填充值的时候,内循环是遍历maxFree,而变量free是可以无限逼近maxFree的,所以在计算restClean时,需要进行判断否则很可能会有数组下标越界的情况。
而在暴力递归过程中,无论怎么清洗咖啡杯,时间都不可能大于maxFree。所以,如果计算的selfClean1变量再加完 wash后,如果 > maxFree,则证明是无效的。在实际过程中不存在这种情况。break。这个值不用填充。

public static int dp(int[] drinks, int wash, int air) {int N = drinks.length;int maxFree = 0;for (int i = 0; i < N; i++) {maxFree = Math.max(maxFree, drinks[i]) + wash;}int[][] dp = new int[N + 1][maxFree + 1];for (int index = N - 1; index >= 0; index--) {for (int free = 0; free < maxFree; free++) {int selfClean1 = Math.max(drinks[index], free) + wash;if (selfClean1 > maxFree){break;}int restClean1 = dp[index + 1][selfClean1];int p1 = Math.max(selfClean1, restClean1);int selfClean2 = drinks[index] + air;int restClean2 = dp[index + 1][free];int p2 = Math.max(selfClean2, restClean2);dp[index][free] = Math.min(p1, p2);}}return dp[0][0];}

完整代码

 public static class Machine {// 咖啡机下一次可以工作的时间int timePoint;//泡一杯咖啡所需时间int workTime;public Machine(int timePoint, int workTime) {this.timePoint = timePoint;this.workTime = workTime;}}public static class MachineComparator implements Comparator<Machine> {@Overridepublic int compare(Machine o1, Machine o2) {return (o1.timePoint + o1.workTime) - (o2.timePoint + o2.hashCode());}}public static int minTime(int[] arr, int N, int a, int b) {PriorityQueue<Machine> heap = new PriorityQueue<>(new MachineComparator());for (int i = 0; i < arr.length; i++) {heap.add(new Machine(0, arr[i]));}int[] drinks = new int[N];for (int i = 0; i < N; i++) {Machine curMachine = heap.poll();drinks[i] = curMachine.timePoint;curMachine.timePoint += curMachine.workTime;heap.add(curMachine);}return process(drinks, a, b, 0, 0);}//drinks: 每个人喝咖啡的最短时间//wash :  用洗咖啡杯机器洗一只咖啡杯的时间// air :  空气挥发一杯咖啡杯的时间//index:  第几只杯子//free : 下一次洗咖啡杯机器可用时间public static int process(int[] drink, int wash, int air, int index, int free) {//没有杯子了if (index == drink.length) {return 0;}//选择洗int selfClean1 = Math.max(drink[index], free) + wash;int restClean1 = process(drink, wash, air, index + 1, selfClean1);int p1 = Math.max(selfClean1, restClean1);// 选择风干int selfClean2 = drink[index] + air;int restClean2 = process(drink, wash, air, index + 1, free);int p2 = Math.max(selfClean2, restClean2);return Math.min(p1, p2);}public static int minTime2(int[] arr, int N, int a, int b) {PriorityQueue<Machine> heap = new PriorityQueue<>(new MachineComparator());for (int i = 0; i < arr.length; i++) {heap.add(new Machine(0, arr[i]));}int[] drinks = new int[N];for (int i = 0; i < N; i++) {Machine curMachine = heap.poll();drinks[i] = curMachine.timePoint;curMachine.timePoint += curMachine.workTime;heap.add(curMachine);}return dp(drinks, a, b);}public static int dp(int[] drinks, int wash, int air) {int N = drinks.length;int maxFree = 0;for (int i = 0; i < N; i++) {maxFree = Math.max(maxFree, drinks[i]) + wash;}int[][] dp = new int[N + 1][maxFree + 1];for (int index = N - 1; index >= 0; index--) {for (int free = 0; free < maxFree; free++) {int selfClean1 = Math.max(drinks[index], free) + wash;if (selfClean1 > maxFree){break;}int restClean1 = dp[index + 1][selfClean1];int p1 = Math.max(selfClean1, restClean1);int selfClean2 = drinks[index] + air;int restClean2 = dp[index + 1][free];int p2 = Math.max(selfClean2, restClean2);dp[index][free] = Math.min(p1, p2);}}return dp[0][0];}

相关文章:

暴力递归转动态规划(九)

题目 题有点难&#xff0c;但还挺有趣 有一个咖啡机数组arr[]&#xff0c;其中arr[i]代表每一个咖啡机冲泡咖啡所需的时间&#xff0c;有整数N&#xff0c;代表着准备冲咖啡的N个人&#xff08;假设这个人拿到咖啡后喝完的时间为0&#xff0c;拿手里咖啡杯即变空&#xff09;&a…...

Linux知识点 -- 高级IO(一)

Linux知识点 – 高级IO&#xff08;一&#xff09; 文章目录 Linux知识点 -- 高级IO&#xff08;一&#xff09;一、5种IO模型1.IO再理解2.阻塞IO3.非阻塞轮询式IO4.信号驱动IO5.IO多路转接6.异步IO7.同步通信vs异步通信8.阻塞vs非阻塞 二、非阻塞IO1.设置非阻塞的方法2.非阻塞…...

Android AMS——内存回收机制(十二)

在 Android 中,AMS(Activity Manager Service)负责管理应用程序的生命周期和资源分配。其中,AMS也包含了内存回收机制,用于释放系统中不再使用的内存资源,以保证系统的稳定性和性能。 一、内存回收简介 1、回收机制 Android AMS 的内存回收机制主要涉及以下几个方面:…...

1600*C. Add One(数位DP找规律)

Problem - 1513C - Codeforces 解析&#xff1a; 考虑DP&#xff0c;DP[ i ] 为从 0 开始执行 i 次操作&#xff0c;此时数字的位数。 我们发现当一个9再操作一次就会变成1和0&#xff0c;并且相邻的大部分长度都不会变化&#xff0c;0会影响10次操作之后的位数&#xff0c;1会…...

干货丨送你几个实用PR编辑技巧(二) 优漫动游

小编认为无论看什么书或教程&#xff0c;都不应该脱离实际去学习PR技巧&#xff0c;基础理论与实践相结合&#xff0c;才能达到比较好的学习和应用效果。 技巧一 如果项目板里有很多素材&#xff0c;很难看清楚哪些素材是已经用过的&#xff0c;哪些是没用过的话&#xff0…...

[每周一更]-(第67期):docker-compose 部署php的laravel项目

容器化部署laravel框架的php项目 操作步骤 参考&#xff1a; https://www.cnblogs.com/jingjingxyk/p/16842937.htmlhttps://developer.aliyun.com/article/708976 0、plv项目修改 composer install.env 修改后台地址 IP:端口chmod -R 777 public / chmod -R 777 storagevi…...

vsCode 忽略 文件上传

1 无 .gitignore 文件时&#xff0c;在项目文件右键&#xff0c;Git Bash 进入命令行 输入 touch .gitignore 生成gitignore文件 2 、在文件.gitignore里输入 node_modules/ dist/ 来自于&#xff1a;vscode git提交代码忽略node_modules_老妖zZ的博客-CSDN博客...

197、管理 RabbitMQ 的虚拟主机

开启Rabbitmq的一些命令&#xff1a; 小黑窗输入&#xff1a; rabbitmq-plugins enable rabbitmq_management 启动控制台插件&#xff0c; 就是启动登录rabbitmq控制台的页面&#xff0c;rabbitmq_management 代表了RabbitMQ的管理界面。 rabbitmq-server 启动rabbitMQ服务器…...

[NCTF2019]SQLi regexp 盲注

/robots.txt 访问一下 $black_list "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\|| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";If $_POST[passwd] admi…...

通过webpack创建并打包js库到npm仓库

1.创建项目并进行基本配置 webpack配置文件&#xff1a; webpack.build.js const path require(path);module.exports {mode:development,entry:./src/webpack-numbers.js,output: {filename: webpack-numbers.js,path: path.resolve(__dirname, dist),clean: true,},}; p…...

【Java 进阶篇】深入了解JavaScript中的函数

函数是JavaScript编程中的核心概念之一。它们是可重用的代码块&#xff0c;可以帮助您组织和管理程序&#xff0c;使您的代码更具可读性和可维护性。在本篇博客中&#xff0c;我们将深入了解JavaScript中的函数&#xff0c;包括函数的基本语法、参数、返回值、作用域、闭包和高…...

谷歌 Chrome 浏览器正推进“追踪保护”功能

导读近日消息&#xff0c;根据国外科技媒体 Windows Latest 报道&#xff0c;谷歌计划在 Chrome 浏览器中推进“追踪保护”&#xff08;Tracking Protection&#xff09;功能&#xff0c;整合浏览器现有隐私功能&#xff0c;保护用户被网站跟踪。 根据一项 Chromium 提案&…...

Excel 自动提取某一列不重复值

IFERROR(INDEX($A$1:$A$14,MATCH(0,COUNTIF($C$1:C1,$A$1:$A$14),0)),"")注意&#xff1a;C1要空置&#xff0c;从C2输入公式 参考&#xff1a; https://blog.csdn.net/STR_Liang/article/details/105182654 https://zhuanlan.zhihu.com/p/55219017?utm_id0...

【TensorFlow2 之011】TF 如何使用数据增强提高模型性能?

一、说明 亮点&#xff1a;在这篇文章中&#xff0c;我们将展示数据增强技术作为提高模型性能的一种方式的好处。当我们没有足够的数据可供使用时&#xff0c;这种方法将非常有益。 教程概述&#xff1a; 无需数据增强的训练什么是数据增强&#xff1f;使用数据增强进行训练可视…...

Hadoop 安装教程 (Mac m1/m2版)

安装JDK1.8 这里最好是安装1.8版本的jdk 1. 进入官网Java Downloads | Oracle Hong Kong SAR, PRC,下滑到中间区域找到JDK8 2.选择mac os,下载ARM64 DMG Installer对应版本 注&#xff1a;这里下载需要注册oracle账号&#xff0c;不过很简单&#xff0c;只需要提供邮箱即可&…...

Docker - 网络模式与容器网络互连

前言 简单记录一下在Docker学习过程中&#xff0c;关于网络模式和容器网络互连的基本概念。 一、Docker的网络模式 &#xff08;1&#xff09;桥接模式&#xff1a;Docker会为每个容器创建一个虚拟网卡&#xff0c;并将这些虚拟网卡连接到一个虚拟交换机上&#xff0c;从而实…...

【基础篇】三、Flink集群角色、系统架构以及作业提交流程

文章目录 1、集群角色2、部署模式3、Flink系统架构3.1 作业管理器&#xff08;JobManager&#xff09;3.2 任务管理器&#xff08;TaskManager&#xff09; 4、独立部署会话模式下的作业提交流程5、Yarn部署的应用模式下作业提交流程 1、集群角色 Flink提交作业和执行任务&…...

第一个2DGodot游戏-从零开始-逐步解析

视频教程地址&#xff1a;https://www.bilibili.com/video/BV1Hw411v78Y/ 前言 大家好&#xff0c;这一集我将要带领大家完成官方文档里的第一个2DGodot游戏&#xff0c;从零开始&#xff0c;逐步解析&#xff0c;演示游戏的制作全过程&#xff0c;尽量让&#xff0c;就算是新…...

大数据学习(7)-hive文件格式总结

&&大数据学习&& &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 承认自己的无知&#xff0c;乃是开启智慧的大门 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一下博>主哦&#x…...

GRU的 电影评论情感分析 - python 深度学习 情感分类 计算机竞赛

1 前言 &#x1f525;学长分享优质竞赛项目&#xff0c;今天要分享的是 &#x1f6a9; GRU的 电影评论情感分析 - python 深度学习 情感分类 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 这…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...