20240105-工作安排的最大收益

题目要求

我们有 n 份工作,每份工作都安排在 startTime[i] 至 endTime[i] 期间完成,从而获得 profit[i] 的利润。

给你 startTime、endTime 和 profit 数组,返回你能获得的最大利润,使得子集中没有两个时间范围重叠的工作。

如果你选择了一项在 X 时间结束的工作,你就可以开始另一项在 X 时间开始的工作。

例子

Input: startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
Output: 120
Explanation: The subset chosen is the first and fourth job. 
Time range [1-3]+[3-6] , we get profit of 120 = 50 + 70.

Input: startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60]
Output: 150
Explanation: The subset chosen is the first, fourth and fifth job. 
Profit obtained 150 = 20 + 70 + 60.

Input: startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4]
Output: 6

思路

这个题目看起来似乎是一个递归问题(背包),在有限的时间内放下最多的工作(产生最大的价值?)但是仔细一想每个工作由起始结束时间决定,并不仅仅是工作时长的大小(可以直接放到背包中)。因此我又想是否使用深度优先搜索解决这个问题。似乎可行...

这次的深度优先搜索需要遍历所有的可能情况,然后返回最优的profit值。

终止条件

那么深搜的终止条件是什么,显而易见就是最后一个工作的截至时间之后,不能再有其他的工作,即:

if (当前工作的截止时间之后没有其他工作) {
        maxprofit = max(profit, maxprofit);
        return;
    }
bool hasNext = false;
        for (int i = start + 1; i < startTime.size(); ++i) {
            if (endTime[start] < startTime[i]) {
                hasNext = true;
                break;
            }
        }
        
        if (!hasNext) {
            maxprofit = max(maxprofit, currentProfit);
            return;
        }

回溯

for (int i = start; i < startTime.size(); ++i) {
            currentProfit += profit[i];
            backtracking(i+1, currentProfit, startTime, endTime, profit);
            currentProfit -= profit[i];
        }

 目前已经完成了回溯:深搜(其实好像不太能抽象成一棵树)算法,但是目前还没有正确的处理时间冲突(即i+1的部分),修改后代码如下,

class Solution {
public:
    int maxprofit = -1;

    void backtracking(int startIndex, int lastEnd, int currentProfit, const vector<int>& startTime, const vector<int>& endTime, const vector<int>& profit) {
        // bool hasNext = false;
        // for (int i = 0; i < startTime.size(); ++i) {
        //     if (lastEnd < startTime[i]) {
        //         hasNext = true;
        //         break;
        //     }
        // }
        
        // if (!hasNext) {
        //     maxprofit = max(maxprofit, currentProfit);
        //     return;
        // }
        maxprofit = max(maxprofit, currentProfit);

        for (int i = startIndex; i < startTime.size(); ++i) {
            if (startTime[i] < lastEnd) {
                continue;
            }
            currentProfit += profit[i];
            printf("Position: %d, currentProfit: %d, maxProfit: %d", i, currentProfit, maxprofit);
            backtracking(i+1, endTime[i], currentProfit, startTime, endTime, profit);
            currentProfit -= profit[i];
        }
    }

    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
        int n = startTime.size();
        vector<int> jobs(n);
        iota(jobs.begin(), jobs.end(), 0); // 填充索引

        // 根据 startTime 排序索引
        sort(jobs.begin(), jobs.end(), [&](int a, int b) {
            return startTime[a] < startTime[b];
        });

        // 重新排列 startTime、endTime 和 profit
        vector<int> sortedStartTime(n), sortedEndTime(n), sortedProfit(n);
        for (int i = 0; i < n; ++i) {
            sortedStartTime[i] = startTime[jobs[i]];
            sortedEndTime[i] = endTime[jobs[i]];
            sortedProfit[i] = profit[jobs[i]];
        }

        backtracking(0, -1, 0, sortedStartTime, sortedEndTime, sortedProfit);
        return maxprofit;
    }
};

结果是超时了。

重新寻找另外的思路,

思路还是类似的,不过转而采用动态规划。

class Solution {
public:
    int memo[50001];

    int findMaxProfit(vector<vector<int>>& jobs, vector<int>& start, int n, int position) {
        if (position == n) {
            return 0;
        }
        if (memo[position] != -1) {
            return memo[position];
        }
        int nextIndex = lower_bound(start.begin(), start.end(), jobs[position][1]) - start.begin();
        int maxProfit = max(findMaxProfit(jobs, start, n, position+1),
                            jobs[position][2] + findMaxProfit(jobs, start, n, nextIndex));
        return memo[position] = maxProfit;
    }

    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
        vector<vector<int>> jobs;
        memset(memo, -1, sizeof(memo));
        for (int i = 0; i < profit.size(); ++i) {
            jobs.push_back({startTime[i], endTime[i], profit[i]});
        }
        sort(jobs.begin(), jobs.end());

        for (int i = 0; i < profit.size(); ++i) {
            startTime[i] = jobs[i][0];
        }
        return findMaxProfit(jobs, startTime, profit.size(), 0);
    }
};

状态转移方程

  • maxProfit = max(findMaxProfit(..., position+1), jobs[position][2] + findMaxProfit(..., nextIndex))
  • 这个方程表示当前最大利润是两种选择中的较大值:要么跳过当前工作(只考虑下一个工作,即position+1),要么选择当前工作(当前工作的利润加上从nextIndex开始的后续工作的最大利润)。

复杂度分析

  • 时间复杂度:排序工作的时间复杂度为O(n log n)。记忆化搜索的时间复杂度大约为O(n),因为每个工作最多被考虑一次。因此,总的时间复杂度大约为O(n log n)。
  • 空间复杂度:主要由记忆化数组memo和工作数组jobs决定,这两者的空间复杂度都是O(n)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SSH 无密登录配置

1)配置 ssh (1)基本语法 ssh 另一台电脑的 IP 地址 (2)ssh 连接时出现 Host key verification failed 的解决方法 [yuxuan@yuxuan102 ~]$ ssh yuxuan103 ➢ 如果出现如下内容 Are you sure you want to continue connecting (yes/no)? ➢ 输入 yes,并回车 (3)退回到 …

MYSQL 存储过程/存储函数

简而言之&#xff0c;类似于封装函数 特点 基本语法 create peocedure p1() begin select coun(*) from studuent; end; call p1(); 设置完别忘了把delimiter改回来 变量 系统变量 用户自定义变量 set myname its; set myage : 10; 局部变量 if 参数&#xff08;IN&…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)线程池的启动和从线程池中取出一个反应堆实例

一、线程池的启动 &#xff08;主线程&#xff09; // 启动线程池 &#xff08;主线程&#xff09; void threadPoolRun(struct ThreadPool* pool) {/*线程池被创建出来之后&#xff0c;接下来就需要让线程池运行起来&#xff0c;其实就是让线程池里的若干个子线程运行起来*//…

JVM虚拟机的垃圾回收器(面试题)

1.什么是垃圾回收 垃圾回收主要说的是java会自动把程序在运行过程中产生的一些没有用的对象给回收掉&#xff0c;这样可以避免内存的浪费。 java主要是通过一个叫“根可达”的算法来识别这个对象是否可以被回收的&#xff0c;然后回收的算法也主要有三种&#xff1a;标记清除&a…

Python 教程 02:Python 编程环境的搭建与 IDE 的选择

目录 一、搭建 Python 环境 1.1 Python 官网 1.2 下载 Python 1.2.1 选择版本 1.2.2 选择平台 1.2.3 下载安装文件&#xff08;Windows & macOS&#xff09; 1.3 安装环境 1.3.1 Windows 平台 1.3.2 macOS 平台 1.3.3 Linux 平台 1.4 验证安装是否成功 二、选择…

Flink自定义Source模拟数据流

maven依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.…

瓢虫目标检测数据集VOC格式400张

瓢虫&#xff0c;一种小巧玲珑、色彩鲜艳的昆虫&#xff0c;因其独特的形态和生态习性而受到广泛欢迎。 瓢虫的体型小巧&#xff0c;一般为圆球形&#xff0c;体色鲜艳&#xff0c;有红、黄、黑等多种颜色。它们通常有一个坚硬的外壳&#xff0c;可以保护自己不受天敌的侵害。…

12月笔记

#pragma once 防止多次引用头文件&#xff0c;保证同一个&#xff08;物理意义上&#xff09;文件被多次包含&#xff0c;内容相同的两个文件同样会被包含。 头文件.h与无.h的文件&#xff1a; iostream是C的头文件&#xff0c;iostream.h是C的头文件&#xff0c;即标准的C头文…

前端--基础 常用标签 - 超链接标签 ( 内部链接,空链接,下载链接,网页元素连接)

链接分类 &#xff1a; 外部链接 内部链接 空链接 下载链接 网页元素链接 内部链接 &#xff1a; 即 网站内部页面之间的相互链接&#xff0c;直接点击 链接内部页面名称即可 所谓内部链接&#xff0c;就是在同一个网站里面&#xff0c;有许多链接&#xff0c;当你在 a…

机器学习笔记 - 用于语义图像分割的空洞卷积DeepLabv3

一、什么是DeepLabv3&#xff1f; DeepLabv3 是用于语义分割任务的深度神经网络 (DNN) 架构。虽然不是比较新的网络模型&#xff0c;但是也是分割模型里的杰出代表之一&#xff0c;所以还是值得深入了解。 它使用Atrous&#xff08;Dilated&#xff09;卷积来控制感受野和特征图…

房贷计算器,妥妥的数学计算

根据给出的公式&#xff0c;编写房贷计算器。妥妥的数学计算&#xff0c;把数学公式“翻译”成代码就好。 (笔记模板由python脚本于2024年01月06日 18:08:55创建&#xff0c;本篇笔记适合初具基本编程能力的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;http…

服务器GPU温度过高挂掉排查记录

服务器GPU挂掉 跑深度学习的代码的时候发现中断了。通过命令查看&#xff1a; nvidia-smi显示 Unable to determine the device handle for GPU 0000:01:00.0: Unknown Error。感觉很莫名其妙。通过重启大法之后&#xff0c;又能用一段时间。 shutdown -r now但是过了一个小…

遗传算法(GA)、模拟退火算法(SAA)、蚁群算法(ACO)、粒子群算法(PSO)优缺点汇总

遗传算法 优点&#xff1a; 与问题领域无关且快速随机的搜索能力&#xff0c;不会陷入局部最优解&#xff1b;搜索从群体出发&#xff0c;具有潜在的并行性&#xff0c;提高运行速度&#xff0c;鲁棒性高&#xff1b;搜索使用评价函数启发&#xff0c;过程简单&#xff1b;使…

基于Java实现全功能电子商城

&#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩项目推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 基于SpringBoot的旅游网站 基于SpringBoot的MusiQ音乐网站 感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及…

小游戏实战丨基于PyGame的俄罗斯方块小游戏

文章目录 写在前面PyGame五子棋注意事项系列文章写在后面 写在前面 本期内容&#xff1a;基于pygame的俄罗斯方块小游戏 下载地址&#xff1a;https://download.csdn.net/download/m0_68111267/88700182 实验环境 python3.11及以上pycharmtkinter PyGame Pygame是一个非常…

Java设计模式-模板方法模式

目录 一、豆浆制作问题 二、模板方法模式基本介绍 三、原理类图 四、模板方法模式解决豆浆制作问题 五、模板方法模式的钩子方法 六、模板方法模式在Spring框架应用的源码分析 七、注意事项和细节 一、豆浆制作问题 编写制作豆浆的程序&#xff0c;说明如下 : 1) 制作…

案例098:基于微信小程序的电子购物系统的设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

【大数据进阶第三阶段之Datax学习笔记】使用阿里云开源离线同步工具DataX 实现数据同步

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax快速入门 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax类图 【大数据进阶第三阶段之Datax学习笔记】使用…

RH850P1X芯片学习笔记-A/D Converter (ADCF)

文章目录 Features of RH850/P1x-C ADCFNumber of UnitsRegister Base AddressClock SupplyInterrupts and DMAHardware ResetExternal Input/Output SignalsVirtual Channel OverviewFunctional OverviewBlock DiagramPhysical Channels, Virtual Channels and Scan Groups Re…

SPRING BOOT发送邮件验证码(Gmail邮箱)

SPRING BOOT邮件发送验证码 一、Gmail邮箱配置 1、进入Gmail(https://mail.google.com) 2、打开谷歌右上角设置 3、启用POP/IMP 4、启用两步验证(https://myaccount.google.com/security) 5、建立应用程式密码 6、复制保存应用程式密码 二、代码 1、引入依赖 <d…