贪心 + 证明:Leetcode 1953. 你可以工作的最大周数

2024-05-16 14:44

本文主要是介绍贪心 + 证明:Leetcode 1953. 你可以工作的最大周数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

描述

给你 n 个项目,编号从 0 到 n - 1 。同时给你一个整数数组 milestones ,其中每个 milestones[i] 表示第 i 个项目中的阶段任务数量。

你可以按下面两个规则参与项目中的工作:

每周,你将会完成 某一个 项目中的 恰好一个 阶段任务。你每周都 必须 工作。
在 连续的 两周中,你 不能 参与并完成同一个项目中的两个阶段任务。
一旦所有项目中的全部阶段任务都完成,或者仅剩余一个阶段任务都会导致你违反上面的规则,那么你将 停止工作 。注意,由于这些条件的限制,你可能无法完成所有阶段任务。

返回在不违反上面规则的情况下你 最多 能工作多少周。

示例 1:
输入:milestones = [1,2,3]
输出:6
解释:一种可能的情形是:
​​​​- 第 1 周,你参与并完成项目 0 中的一个阶段任务。

  • 第 2 周,你参与并完成项目 2 中的一个阶段任务。
  • 第 3 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 4 周,你参与并完成项目 2 中的一个阶段任务。
  • 第 5 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 6 周,你参与并完成项目 2 中的一个阶段任务。
    总周数是 6 。

示例 2:
输入:milestones = [5,2,1]
输出:7
解释:一种可能的情形是:

  • 第 1 周,你参与并完成项目 0 中的一个阶段任务。
  • 第 2 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 3 周,你参与并完成项目 0 中的一个阶段任务。
  • 第 4 周,你参与并完成项目 1 中的一个阶段任务。
  • 第 5 周,你参与并完成项目 0 中的一个阶段任务。
  • 第 6 周,你参与并完成项目 2 中的一个阶段任务。
  • 第 7 周,你参与并完成项目 0 中的一个阶段任务。
    总周数是 7 。
    注意,你不能在第 8 周参与完成项目 0 中的最后一个阶段任务,因为这会违反规则。
    因此,项目 0 中会有一个阶段任务维持未完成状态。

思路

贪心,每次选择两个耗时最大的工作花两周完成,但这样会导致超时。

注意到当耗时最大的工作非常大时,剩余任务都可以完成,因此考虑最大工作耗时与剩余工作耗时的关系。

解题方法

设最大工作耗时为longest,剩余工作耗时为rest,那么:

当longest > rest时,显然可证最大工作周数为:2∗rest+1

当longest = rest时,显然可证最大工作周数为:rest+longest,即工作总和

当longest<rest时,在rest的任务范围内,一定可以被工作,直至rest′=longest,此时回到上面“longest=rest”的状态,因此总的工作耗时为rest+longet

为什么在rest的任务范围内,一定可以被工作,直至rest′=longest的状态?
证明:此时可以反证,假设rest不可以被工作以减少剩余工作量,那么rest只能剩一个工作任务,但由于rest>longest,可以得到该工作任务量大于longest,这和最大工作耗时为longest矛盾。

代码

class Solution {
public:long long numberOfWeeks(vector<int>& milestones) {// 耗时最长工作所需周数long long longest = *max_element(milestones.begin(), milestones.end());// 其余工作共计所需周数long long rest = accumulate(milestones.begin(), milestones.end(), 0LL) - longest;if (longest > rest + 1){// 此时无法完成所耗时最长的工作return rest * 2 + 1;}else {// 此时可以完成所有工作return longest + rest;}}
};

再附上一个超时的暴力贪心代码,太笨了花了一个小时只能做出这个版本的…

class Solution:def numberOfWeeks(self, milestones: List[int]) -> int:# 贪心模拟heap = []for task_no,task_num in enumerate(milestones):heappush(heap,(-task_num,task_no))#last_task_no = -1work_weeks = 0while(len(heap) > 1):task_num1,task_no1 = heappop(heap)task_num2,task_no2 = heappop(heap)task_num1 *= -1task_num2 *= -1#last_task_no = task_no2if(len(heap) == 0):work_weeks += 2*task_num2if(task_num1 != task_num2): work_weeks += 1return work_weekstask_num3 = heap[0][0]task_num3 *= -1temp = task_num2 - task_num3 + 1task_num1 -= temptask_num2 -= tempwork_weeks += 2*tempif(task_num2 != 0):heappush(heap,(-task_num2,task_no2))heappush(heap,(-task_num1,task_no1))elif(task_num1 != 0):heappush(heap,(-task_num1,task_no1))return work_weeks + 1

这篇关于贪心 + 证明:Leetcode 1953. 你可以工作的最大周数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/995202

相关文章

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如

如何提高Redis服务器的最大打开文件数限制

《如何提高Redis服务器的最大打开文件数限制》文章讨论了如何提高Redis服务器的最大打开文件数限制,以支持高并发服务,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录如何提高Redis服务器的最大打开文件数限制问题诊断解决步骤1. 修改系统级别的限制2. 为Redis进程特别设置限制

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

usaco 1.3 Barn Repair(贪心)

思路:用上M块木板时有 M-1 个间隙。目标是让总间隙最大。将相邻两个有牛的牛棚之间间隔的牛棚数排序,选取最大的M-1个作为间隙,其余地方用木板盖住。 做法: 1.若,板(M) 的数目大于或等于 牛棚中有牛的数目(C),则 目测 给每个牛牛发一个板就为最小的需求~ 2.否则,先对 牛牛们的门牌号排序,然后 用一个数组 blank[ ] 记录两门牌号之间的距离,然后 用数组 an

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 3723 kruscal,反边取最大生成树。

题意: 需要征募女兵N人,男兵M人。 每征募一个人需要花费10000美元,但是如果已经招募的人中有一些关系亲密的人,那么可以少花一些钱。 给出若干的男女之间的1~9999之间的亲密关系度,征募某个人的费用是10000 - (已经征募的人中和自己的亲密度的最大值)。 要求通过适当的招募顺序使得征募所有人的费用最小。 解析: 先设想无向图,在征募某个人a时,如果使用了a和b之间的关系

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

poj 3258 二分最小值最大

题意: 有一些石头排成一条线,第一个和最后一个不能去掉。 其余的共可以去掉m块,要使去掉后石头间距的最小值最大。 解析: 二分石头,最小值最大。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <c

poj 2175 最小费用最大流TLE

题意: 一条街上有n个大楼,坐标为xi,yi,bi个人在里面工作。 然后防空洞的坐标为pj,qj,可以容纳cj个人。 从大楼i中的人到防空洞j去避难所需的时间为 abs(xi - pi) + (yi - qi) + 1。 现在设计了一个避难计划,指定从大楼i到防空洞j避难的人数 eij。 判断如果按照原计划进行,所有人避难所用的时间总和是不是最小的。 若是,输出“OPETIMAL",若

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回