【OD機試題解法筆記】貪心歌手

題目描述

一個歌手準備從A城去B城參加演出。

  1. 按照合同,他必須在 T 天內趕到
  2. 歌手途經 N 座城市
  3. 歌手不能往回走
  4. 每兩座城市之間需要的天數都可以提前獲知。
  5. 歌手在每座城市都可以在路邊賣唱賺錢。
    經過調研,歌手提前獲知了每座城市賣唱的收入預期: 如果在一座城市第一天賣唱可以賺M,后續每天的收入會減少D(第二天賺的錢是 M - D,第三天是 M - 2D …)。如果收入減少到 0 就不會再少了。
  6. 歌手到達后的第二天才能開始賣唱。如果今天賣過唱,第二天才能出發。
    貪心的歌手最多可以賺多少錢

輸入描述
第一行兩個數字 T 和 N,中間用空格隔開。

  • T 代表總天數,0 < T < 1000
  • N 代表路上經過 N 座城市,0 < N < 100

第二行 N+1 個數字,中間用空格隔開。代表每兩座城市之間耗費的時間。

  • 其總和 ≤ T。

接下來 N 行,每行兩個數字 M 和 D,中間用空格隔開。代表每個城市的收入預期。

  • 0 < M < 1000
  • 0 < D < 100

用例
輸入

10 2
1 1 2
120 20
90 10

輸出

540

說明
總共10天,路上經過2座城市。
路上共花 1+1+2=4 天
剩余6天最好的計劃是在第一座城市待3天,在第二座城市待3天。
在第一座城市賺的錢:120 + 100 + 80 = 300
在第二座城市賺的錢:90 + 80 + 70 = 240
一共 300 + 240 = 540。

思考

先計算除去路上花費的天數后剩余可分配天數,在 N 個城市中按順序賣唱的最大收益。用例中的數據,城市1的日收益如下:
120 100 80 60 40 20,城市2 的日收益: 90 80 70 60 50 40,假如剩余天數是6天,都在第一座城市賣唱,那么收益數組為:
[120,100,80,60,40,20],顯然后3天的收益 [60,40,20] 小于第二座城市前3天的收益 [90,80,70],那么最大收益就是第一座城市停留3天收益+第二座城市停留3天的收益,即[120,100,80,90,80,70]。具體算法應該是先按順序遍歷每座經過的城市,對每個城市,假設剩余天數都停留在這座城市,得到一個收益列表 profits;下一輪循環遍歷下一座城市時重復之前操作,但把收益列表中最小的收益數替換為當前更大的收益,這樣最終的收益列表profits盡可能包含了每座城市中最大的收益數,即是整個歌手能獲得的最大賣唱收益。可以用優先隊列快速獲取最小收益,并將較大收益數入隊,優化時間復雜度。有些編程語言沒有內置優先隊列,不熟悉實現起來比較耗費時間,比如JavaScript,可以用數組模擬下,如:let minIndex = queue.lastIndexOf(Math.min(...queue)), queue[minIndex] = curElem;,只要做題時能通過就行。

算法過程

該算法基于最小優先隊列(Min-Heap) 實現,核心思路是:從所有城市的可能賣唱日收益中,篩選出最大的leftDays個收益(leftDays為可用于賣唱的剩余天數),總和即為最大總收益。具體步驟如下:

步驟1:計算可用于賣唱的剩余天數
  • 首先計算總路程耗時:將輸入的N+1段路程時間求和(記為totalRoadDays)。
  • 剩余可賣唱天數為:leftDays = T - totalRoadDays。若leftDays ≤ 0,則無時間賣唱,直接返回0。
步驟2:初始化最小優先隊列
  • 使用最小優先隊列(堆)存儲當前篩選出的最大日收益,隊列最多容納leftDays個元素(因為總共有leftDays天可賣唱)。
  • 最小優先隊列的特性是:頂部元素始終是當前隊列中最小的元素,便于快速替換為更大的收益。
步驟3:遍歷所有城市,計算并篩選日收益

對于每座城市,按順序計算在該城市停留第1天、第2天……直到第leftDays天的日收益(超過leftDays天的收益無需計算,因為總天數有限),并按規則加入隊列:

  • 日收益計算規則:第j天(j從1開始)的收益為 max(M - D*(j-1), 0)M為初始收益,D為每日遞減值,收益不能為負)。
  • 隊列操作規則
    • 若隊列元素數量 < leftDays:直接將當前日收益加入隊列(此時需要填充所有可能的天數)。
    • 若隊列已滿(元素數量 = leftDays):比較當前日收益與隊列頂部的最小收益。若當前收益更大,則移除隊列中最小的收益,將當前收益加入隊列(保證隊列始終保留目前最大的leftDays個收益)。
步驟4:計算最大總收益

當所有城市的所有可能日收益都處理完畢后,隊列中存儲的是最大的leftDays個日收益。將這些收益求和,即為歌手能獲得的最大總收益。

示例驗證(對應題目用例)

  1. 計算剩余天數:總天數T=10,路程時間1+1+2=4,故leftDays=6
  2. 處理第一座城市(M=120,D=20)
    • 日收益依次為:120(第1天)、100(第2天)、80(第3天)、60(第4天)、40(第5天)、20(第6天)。
    • 隊列初始為空,依次加入這6個收益,隊列元素為[20,40,80,60,100,120](堆頂為最小元素20)。
  3. 處理第二座城市(M=90,D=10)
    • 日收益依次為:90(第1天)、80(第2天)、70(第3天)、60(第4天)、50(第5天)、40(第6天)。
    • 逐個處理:
      • 90 > 堆頂20 → 移除20,加入90 → 隊列元素更新(堆頂40)。
      • 80 > 堆頂40 → 移除40,加入80 → 隊列元素更新(堆頂60)。
      • 70 > 堆頂60 → 移除60,加入70 → 隊列元素更新(堆頂70)。
      • 60、50、40均小于堆頂70 → 不加入隊列。
  4. 求和隊列元素:最終隊列元素為70,80,80,90,100,120,總和為70+80+80+90+100+120=540,與用例結果一致。

算法核心邏輯

通過最小優先隊列動態維護最大的leftDays個日收益,利用每個城市日收益單調遞減的特性(每天收益≤前一天),確保篩選出的收益是全局最優的。該方法時間復雜度為O(N×leftDays×log(leftDays)),高效適用于題目約束(N<100leftDays<T<1000)。

參考代碼

class MinPriorityQueue {constructor() {this._data = [];}enqueue(e) {this._data.push(e);this.swim();}dequeue() {this._data.shift();if (this.isEmpty()) return;let lastElem = this._data.pop();this._data.unshift(lastElem);this.sink();}swim() {const n = this._data.length;let index = n - 1;while (index > 0) {let parentIndex = Math.floor((index-1)/2);if (this._data[index] < this._data[parentIndex]) {[this._data[parentIndex], this._data[index]] = [this._data[index], this._data[parentIndex]];index = parentIndex;continue;}break;}}sink() {let index = 0;const n = this._data.length;while (true) {let left = 2 * index + 1;let right = left + 1;let smallest = index;if (left < n && this._data[left] < this._data[index]) {smallest = left;}if (right < n && this._data[right] < this._data[smallest]) {smallest = right;}if (smallest !== index) {[this._data[smallest], this._data[index]] = [this._data[index], this._data[smallest]];index = smallest;continue;}break;}}top() {return this._data[0];}isEmpty() {return this._data.length === 0;}size() {return this._data.length;}
}function solution() {const [T, N] = readline().split(' ').map(Number);const times = readline().split(' ').map(Number);const cities = [];for (let i = 0; i < N; i++) {cities[i] = readline().split(' ').map(Number);}const leftDaysNum = T - times.reduce((cur,acc) => cur + acc);const profits = new MinPriorityQueue();for (let i = 0; i < N; i++) {for (let j = 0; j < leftDaysNum; j++) {let curProfit = Math.max(cities[i][0] - cities[i][1] * j, 0);if (curProfit === 0) {break;}if (profits.size() < leftDaysNum) {profits.enqueue(curProfit);} else {if (curProfit > profits.top()) {profits.dequeue();profits.enqueue(curProfit);}}}}let result = 0;while (profits.size()) {result += profits.top();profits.dequeue();}console.log(result);
}const cases = [`10 2
1 1 2
120 20
90 10`,
];let caseIndex = 0;
let lineIndex = 0;const readline = (function () {let lines = [];return function () {if (lineIndex === 0) {lines = cases[caseIndex].trim().split("\n").map((line) => line.trim());}return lines[lineIndex++];};
})();cases.forEach((_, i) => {caseIndex = i;lineIndex = 0;solution();
});

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/917173.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/917173.shtml
英文地址,請注明出處:http://en.pswp.cn/news/917173.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI: 告別過時信息, 用RAG和一份PDF 為LLM打造一個隨需更新的“外腦”

嘿&#xff0c;各位技術同學&#xff01;今天&#xff0c;我們來聊一個大家在使用大語言模型&#xff08;LLM&#xff09;時都會遇到的痛點&#xff1a;知識過時。 無論是像我一樣&#xff0c;用 Gemini Pro 學習日新月異的以太坊&#xff0c;還是希望它能精確掌握某個特定工具…

深度學習(魚書)day08--誤差反向傳播(后三節)

深度學習&#xff08;魚書&#xff09;day08–誤差反向傳播&#xff08;后三節&#xff09;一、激活函數層的實現 這里&#xff0c;我們把構成神經網絡的層實現為一個類。先來實現激活函數的ReLU層和Sigmoid層。ReLU層 激活函數ReLU&#xff08;Rectified Linear Unit&#xff…

C# 中生成隨機數的常用方法

1. 使用 Random 類&#xff08;簡單場景&#xff09; 2. 使用 RandomNumberGenerator 類&#xff08;安全場景&#xff09; 3. 生成指定精度的隨機小數 C# 中生成隨機數的常用方法&#xff1a; 隨機數類型實現方式示例代碼特點與適用場景隨機整數&#xff08;無范圍&#xf…

Flink 算子鏈設計和源代碼實現

1、JobGraph &#xff08;JobManager&#xff09; JobGraph 生成時&#xff0c;通過 ChainingStrategy 連接算子&#xff0c;最終在 Task 中生成 ChainedDriver 鏈表。StreamingJobGraphGeneratorcreateJobGraph() 構建jobGrapch 包含 JobVertex setChaining() 構建算子鏈isCha…

對接八大應用渠道

背景最近公司想把游戲包上到各個渠道上&#xff0c;因此需要對接各種渠道&#xff0c;渠道如下&#xff0c;oppo、vivo、華為、小米、應用寶、taptap、榮耀、三星等應用渠道 主要就是對接登錄、支付接口&#xff08;后續不知道會不會有其他的&#xff09;&#x…

學習:入門uniapp Vue3組合式API版本(17)

42.打包發行微信小程序的上線全流程 域名 配置 發行 綁定手機號 上傳 提交后等待&#xff0c;上傳 43.打包H5并發布上線到unicloud的前端頁面托管 完善配置 unicloud 手機號實名信息不一致&#xff1a;請確保手機號的實名信息與開發者姓名、身份證號一致&#xff0c;請前往開…

SOLIDWORKS材料明細表設置,屬于自己的BOM表模板

上一期我們了解了如何在SOLIDWORKS工程圖中添加材料明細表?接下來&#xff0c;我們將進行對SOLIDWORKS材料明細表的設置、查看縮略圖、模板保存的深度講解。01 材料明細表設置菜單欄生成表格后左側菜單欄會顯示關于材料明細表的相關設置信息。我們先了解一下菜單欄設置詳情&am…

全棧:Maven的作用是什么?本地倉庫,私服還有中央倉庫的區別?Maven和pom.xml配置文件的關系是什么?

Maven和pom.xml配置文件的關系是什么&#xff1a; Maven是一個構建工具和依賴管理工具&#xff0c;而pom.xml&#xff08;Project Object Model&#xff09;是Maven的核心配置文件。 SSM 框架的項目不一定是 Maven 項目&#xff0c;但推薦使用 Maven進行管理。 SSM 框架的項目可…

超越 ChatGPT:智能體崛起,開啟全自主 AI 時代

引言 短短三年,生成式 AI 已從對話助手跨越到能自主規劃并完成任務的“智能體(Agentic AI)”時代。這場演進不僅體現在模型規模的提升,更在于系統架構、交互范式與安全治理的全面革新。本文按時間線梳理關鍵階段與核心技術,為您呈現 AI 智能體革命的脈絡與未來趨勢。 1. …

一杯就夠:讓大腦瞬間在線、讓肌肉滿電的 “Kick-out Drink” 全解析

一杯就夠&#xff1a;讓大腦瞬間在線、讓肌肉滿電的 “Kick-out Drink” 全解析“每天清晨&#xff0c;當鬧鐘還在哀嚎&#xff0c;你舉杯一飲&#xff0c;睡意像被扔出擂臺——這&#xff0c;就是 Kick-out Drink 的全部浪漫。”清晨 30 分鐘后&#xff0c;250 mL 常溫水里溶解…

系統開機時自動執行指令

使用 systemd 創建一個服務單元可以讓系統開機時自動執行指令&#xff0c;假設需要執行的指令如下&#xff0c;運行可執行文件&#xff08;/home/demo/可執行文件&#xff09;&#xff0c;并輸入參數&#xff08;–input/home/config/demo.yaml&#xff09;&#xff1a; /home/…

Docker 初學者需要了解的幾個知識點 (七):php.ini

這段配置是 php.ini 文件中針對 PHP 擴展和 Xdebug 調試工具的設置&#xff0c;主要用于讓 PHP 支持數據庫連接和代碼調試&#xff08;尤其在 Docker 環境中&#xff09;&#xff0c;具體解釋如下&#xff1a;[PHP] extensionpdo_mysql extensionmysqli xdebug.modedebug xdebu…

【高階版】R語言空間分析、模擬預測與可視化高級應用

隨著地理信息系統&#xff08;GIS&#xff09;和大尺度研究的發展&#xff0c;空間數據的管理、統計與制圖變得越來越重要。R語言在數據分析、挖掘和可視化中發揮著重要的作用&#xff0c;其中在空間分析方面扮演著重要角色&#xff0c;與空間相關的包的數量也達到130多個。在本…

dolphinscheduler中一個腳本用于從列定義中提取列名列表

dolphinscheduler中&#xff0c;我們從一個mysql表導出數據&#xff0c;上傳到hdfs, 再創建一個臨時表&#xff0c;所以需要用到列名定義和列名列表。 原來定義兩個變量&#xff0c;不僅繁鎖&#xff0c;還容易出現差錯&#xff0c;比如兩者列序不對。 所以考慮只定義列定義變量…

JavaWeb(蒼穹外賣)--學習筆記16(定時任務工具Spring Task,Cron表達式)

前言 本篇文章是學習B站黑馬程序員蒼穹外賣的學習筆記&#x1f4d1;。我的學習路線是Java基礎語法-JavaWeb-做項目&#xff0c;管理端的功能學習完之后&#xff0c;就進入到了用戶端微信小程序的開發&#xff0c;用戶端開發的流程大致為用戶登錄—商品瀏覽&#xff08;其中涉及…

靈敏度,精度,精確度,精密度,精準度,準確度,分辨率,分辨力——概念

文章目錄前提總結前提 我最近在整理一份數據指標要求的時候&#xff0c;總是混淆這幾個概念&#xff1a;靈敏度&#xff0c;精度&#xff0c;精確度&#xff0c;精密度&#xff0c;精準度&#xff0c;準確度&#xff0c;分辨率&#xff0c;分辨力&#xff0c;搜了一些文章&…

python-異常(筆記)

#后續代碼可以正常運行 try:f open("xxx.txt","r",encodingutf-8)except:print("except error")#捕獲指定異常&#xff0c;其他異常報錯程序中止&#xff0c;管不到 try:print(name) except NameError as you_call:print("name error"…

[lvgl_player] 用戶界面(LVGL) | 播放器核心設計

docs&#xff1a;基于LVGL的音樂播放器 本項目是為嵌入式設備設計的音樂播放系統&#xff0c;采用LVGL圖形庫構建用戶界面。 系統支持播放WAV格式音頻文件&#xff0c;具備播放列表管理功能&#xff0c;可實現播放/暫停控制、曲目切換等核心操作。 用戶可通過交互界面實時調…

數據賦能(354)——數據分析——多角度分析原則

概述重要性如下&#xff1a;獲得全面理解&#xff1a;多角度分析原則避免僅從單一角度解讀數據&#xff0c;從不同角度、不同維度對數據進行分析&#xff0c;以獲得更全面的理解。發現潛在規律&#xff1a;通過多角度分析&#xff0c;發現數據中的潛在規律和趨勢&#xff0c;為…

【華為機試】127. 單詞接龍

文章目錄127. 單詞接龍描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;解題思路算法分析問題本質分析單向BFS算法詳解雙向BFS算法詳解鄰居單詞生成過程算法流程圖邊界情況分析各種解法對比時間復雜度分析空間復雜度分析關鍵優化點實際應用場景圖構建策略雙向BFS優化…