【動態規劃 | 多狀態問題】動態規劃求解多狀態問題

在這里插入圖片描述

算法相關知識點可以通過點擊以下鏈接進行學習一起加油!
斐波那契數列模型路徑問題

多狀態問題通常涉及多個決策點和狀態轉換,解決起來復雜且計算量大。動態規劃作為一種強大的算法工具,能夠通過將問題分解為子問題并逐步求解,顯著提升解決這類問題的效率。本文將探討如何運用動態規劃技術有效處理復雜的多狀態問題,幫助讀者理解其背后的原理,并展示如何設計高效的狀態轉移方程以優化問題求解過程。

請添加圖片描述

Alt

🌈個人主頁:是店小二呀
🌈C/C++專欄:C語言\ C++
🌈初/高階數據結構專欄: 初階數據結構\ 高階數據結構
🌈Linux專欄: Linux
🌈算法專欄:算法
🌈Mysql專欄:Mysql

🌈你可知:無人扶我青云志 我自踏雪至山巔 請添加圖片描述

文章目錄

    • 面試題 17.16. 按摩師
    • 213. 打家劫舍 II
    • 740. 刪除并獲得點數
    • LCR 091. 粉刷房子
    • 309. 買賣股票的最佳時機含冷凍期
    • 714.買賣股票的最佳時機含手續費
    • 123. 買賣股票的最佳時機 III
    • 188. 買賣股票的最佳時機 IV

面試題 17.16. 按摩師

題目】:面試題 17.16. 按摩師

在這里插入圖片描述

算法思路

在這里插入圖片描述

通過題目分析,狀態可以表示為選擇到第 i 位置時的最長預約時長。進一步細化后,題目提供了兩種狀態:是否選擇 nums[i],這會影響最終結果。為此,我們可以創建兩個 DP 表,分別表示選擇或不選擇 nums[i] 的情況,并根據不同狀態進行處理。

題目要求不能連續選擇,因此我們需要根據狀態的定義以及與前一個狀態之間的關系,推導出狀態轉移方程。對于不選擇 nums[i] 的情況,上一狀態的選擇與否都會影響當前的最長預約時長,這與具體的選擇策略密切相關

解決問題的關鍵在于,通過在第 i 位置引入多種狀態,利用動態規劃(DP)來求解。結合題目需求,我們需要確保DP表之間的狀態連續性,從而推導出合理的狀態轉移方程。

代碼實現

class Solution {
public:int massage(vector<int>& nums) {int n = nums.size();if(n == 0) return 0;///1.為多狀態創建dp表vector<int> f(n);vector<int> g(n);//2.初始化f[0] = nums[0];//3.填表for(int i = 1; i < n; i++){f[i] = g[i - 1] + nums[i];g[i] = max(f[i - 1], g[i - 1]);}//4.返回值return max(f[n - 1],g[n - 1]);}
};

213. 打家劫舍 II

題目】:213. 打家劫舍 II

在這里插入圖片描述

算法思路

在這里插入圖片描述

繪圖分析是一種快速的問題分析方法。通過畫圖分析,我們可以根據第一個位置是否選擇,分成兩個部分。剩余部分的處理方式與“面試題 17.16. 按摩師”的解法類似,使用簡單的多狀態動態規劃(DP)方法即可解決。

在解決問題的過程中,可以根據一些特殊條件將問題劃分為子問題,從而使用相同的邏輯來處理這些子問題,這樣有助于簡化并有效解決其中可能存在的特殊情況。

代碼實現

class Solution {
public:int rob(vector<int>& nums) {   int n = nums.size();int ret =max ( nums[0] + rob1(nums, 2, n - 2), rob1(nums,1, n - 1));return ret;}int rob1(vector<int>& nums, int left, int rigth){if(left > rigth) return 0;//1.創建db表int n = nums.size();vector<int> f(n);auto g = f;//2.初始化f[left] = nums[left];//3.填表for(int i = left + 1; i <= rigth; i++){f[i] = g[i - 1] + nums[i];g[i] = max(f[i - 1], g[i - 1]);}return max(f[rigth],g[rigth]);}
};

740. 刪除并獲得點數

題目】:740. 刪除并獲得點數

在這里插入圖片描述

算法思路

在這里插入圖片描述

有些題目可能需要預處理,才能更容易發現使用動態規劃(DP)來解決問題。例如,在這道題中,直接從題目入手使用DP并不可取。我們需要刪除 nums[i] - 1nums[i] + 1 這些元素,換句話說,要跳過這些無法相加的元素。

同時,題目要求獲取最大值,通常在這種情況下,若需要快速查找元素,需要連續下標訪問,哈希表是一個常見的選擇。但在這里,我們只需要根據數組下標來查找元素,元素代表相加點數,數值為下標方便操作,因此可以用數組的下標值作為哈希表的替代,通過這種方式進行DP操作更加簡便。

代碼實現

class Solution {
public:int deleteAndEarn(vector<int>& nums) {//1.預處理const int N = 10001;int arr[N] = {0};for(auto x : nums) arr[x] += x;//2.創建dp表vector<int> f(N);auto g = f;//3.填表操作for(int i = 1; i < N; i++){f[i] = g[i - 1] + arr[i];g[i] = max(f[i - 1], g[i - 1]);}return max(f[N - 1], g[N - 1]);}
};

LCR 091. 粉刷房子

題目】:LCR 091. 粉刷房子

在這里插入圖片描述

算法思路

在這里插入圖片描述
在這里插入圖片描述

屬于很典型的簡單多狀態dp問題,在i位置時候,通過選擇顏色,此時的最小花費。dp細分為三種顏色,在該i位置的最小花費,然后跟最近一次狀態,寫出狀態轉移方程。三個狀態表示相互作用,相互呼應,最后判斷最小就行了。這里建議搞個虛擬節點。

代碼分析

我們可以搭建一個二維數組,其中每個元素代表一個分化的DP表,用來記錄在第 i 位置選擇某種顏色時的最小花費。

根據分析出的狀態轉移方程,可以通過另外兩個DP表獲取前兩個狀態的最小值,并加上當前顏色的花費,從而計算出當前狀態的最小花費。可以將這兩個二維數組視作疊加在一起,三個DP表根據狀態轉移方程共同處理問題,通過這種方式有效地求解最小花費。

感覺面向過程有點難,不如選擇面向對象編程,對于這些問題的處理。

虛擬節點

虛擬節點需要保證后續填表正確性,那么可以圖像結合狀態轉移方程,決定虛擬節點初始化數值。

代碼實現

class Solution {
public:int minCost(vector<vector<int>>& costs) {int n = costs.size();//1.多狀態 創建dp表vector<vector<int>> dp(n + 1,vector<int>(3));//2.初始化操作dp[0][0] = dp[0][1] = dp[0][2] = 0;for(int i = 1; i <= n; i++){dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i - 1][0];dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1];dp[i][2] = min(dp[i - 1][1], dp[i - 1][0]) + costs[i - 1][2]; }return min(dp[n][1], min(dp[n][2], dp[n][0]));}
};

309. 買賣股票的最佳時機含冷凍期

題目】:309. 買賣股票的最佳時機含冷凍期

在這里插入圖片描述

算法思路

在這里插入圖片描述

結合上道題經驗,遇到狀態超過兩種,可以使用0,1,2標識不同狀態標識,dp[i] [0]、dp[i] [1]、dp[i] [2]表示i位置,巴拉巴拉狀態。

常用手段是畫出"狀態機"分析狀態之間轉化,方便寫出動態轉移方程和初始化處理。這里選擇以為i位置結束,所表示狀態。根據狀態機某個位置,結合最近一次位置結合題目分析,寫出然后得到當前位置數值,從而得到狀態轉移方程。

代碼實現

class Solution {
public:int maxProfit(vector<int>& prices) {int n = prices.size();//1.創建多狀態dp表vector<vector<int>> dp(n, vector<int>(3));//2.初始化dp[0][0] = -prices[0];dp[0][1] = dp[0][2] = 0;//3.填表for(int i = 1; i < n; i++){dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]);dp[i][2] = dp[i - 1][0] + prices[i];}return max(dp[n - 1][1], max(dp[n - 1][2], dp[n - 1][0]));}
};

714.買賣股票的最佳時機含手續費

題目】:714. 買賣股票的最佳時機含手續費

在這里插入圖片描述

算法思路

在這里插入圖片描述

首先,根據經驗和題目要求,得出狀態轉移方程。然后選擇合適的i位置進行狀態分析,得到買入狀態和可交易狀態的表示。

接下來,可以通過關聯最近一次的位置來確定狀態轉移方程,或者繪制狀態機圖,將所有狀態轉化過程進行分析。最后,初始化相關位置,通過狀態轉移方程確定初始位置,并在圖中進行分析。

代碼實現

class Solution {
public:int maxProfit(vector<int>& prices, int fee) {//1.創建dp表int n = prices.size();vector<int> f(n);auto g = f;//2.初始化f[0] = -prices[0];g[0] = 0;//3.填表操作for(int i = 1; i < n; i++){f[i] = max(f[i - 1], g[i - 1] - prices[i]);g[i] = max(g[i - 1], f[i - 1] + prices[i] - fee);}return g[n- 1];}
};

123. 買賣股票的最佳時機 III

題目】:123. 買賣股票的最佳時機 III

在這里插入圖片描述

算法思路

在這里插入圖片描述

在解決問題之前,我們需要結合題目和樣例進行繪圖模擬,直觀地展示整個過程。在這里,'最多’的含義是指從0到最大范圍,而并非一定要選擇這么多。

在這里插入圖片描述

首先,根據’經驗 + 題目要求’得到初步的狀態表示,并通過 i 位置進行分析。如果發現該狀態表示不夠充分,可以增加一個位置來表示’完成了多少次交易’。

接下來,繪制狀態機并推導出狀態轉移方程。在處理狀態轉移方程時,需考慮所有細節。例如,題目中的狀態轉移方程可能會涉及越界問題,需在初始化過程中解決這個隱含問題。

特別需要注意的是,第一行位置的初始化應為[1, n - 1]并設置為無窮小,以避免不必要的干擾。此外,初始化某些位置時,要確保它們不會影響后續位置的正確計算,或者確保后續位置能夠正確更新。

代碼實現

class Solution {
public:const int INT = -0x3f3f3f3f;int maxProfit(vector<int>& prices) {//1.創建dp表int n = prices.size();vector<vector<int>> f(n, vector<int>(3,INT));auto g = f;//2.初始化f[0][0] = -prices[0];g[0][0] = 0;//3.填表操作for(int i = 1; i < n; i++){for(int j = 0; j < 3; j++){f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);g[i][j] = j - 1 >= 0 ? max(g[i - 1][j], f[i - 1][j - 1] + prices[i]) : g[i - 1][j];}}int ret = 0;for(int j = 0; j < 3; j++)ret = max(ret, g[n - 1][j]);return ret;}
};

188. 買賣股票的最佳時機 IV

題目】:188. 買賣股票的最佳時機 IV

在這里插入圖片描述

算法思路

首先處理 k 的值,考慮到 k 可能超過所需的總天數,通過數學方法將 k 調整到一個合理范圍內。

在這里插入圖片描述

這道題算法思路同上道題一樣,主要畫出"狀態機"分析狀態轉移方程,同時需要分析狀態轉移方程出現的問題。

在這里插入圖片描述

代碼實現

class Solution {
public:const int INF = -0x3f3f3f3f;int maxProfit(int k, vector<int>& prices) {     int n = prices.size();       k = min(k, n/2);//1.創建dp表      vector<vector<int>> f(n, vector<int>(k + 1, INF));auto g = f;//2.初始化f[0][0] = -prices[0];g[0][0] = 0;//3.填表操作for(int i = 1; i < n; i++){for(int j = 0; j <= k; j++){f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);g[i][j] = g[i - 1][j];if(j - 1 >= 0)g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]);}}int ret = 0;for(int j = 0; j <= k; j++) ret = max(ret, g[n - 1][j]);return ret;}
};

在這里插入圖片描述
快和小二一起踏上精彩的算法之旅!關注我,我們將一起破解算法奧秘,探索更多實用且有趣的知識,開啟屬于你的編程冒險!

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

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

相關文章

【HTTP】防XSS+SQL注入:自定義HttpMessageConverter過濾鏈深度解決方案

防XSSSQL注入&#xff1a;自定義HttpMessageConverter過濾鏈深度解決方案一、安全威脅模型分析二、自定義HttpMessageConverter架構設計2.1 技術棧組成三、完整實現代碼3.1 安全過濾工具類3.2 自定義HttpMessageConverter3.3 Spring安全配置四、深度防御增強方案4.1 SQL注入參數…

學習游戲制作記錄(凍結敵人時間與黑洞技能)7.30

1.實現劍擊中敵人時凍結敵人時間Enemy腳本&#xff1a;public float defaultMoveSpeed;//默認速度defaultMoveSpeed moveSpeed;//Awake&#xff08;&#xff09;中設置public virtual void FreezeTime(bool _timeFreeze)//凍結設置函數{if (_timeFreeze){moveSpeed 0;anim.sp…

【數據結構】真題 2016

待補充已知表頭元素為c的單鏈表在內存中的存儲狀態如下表所示地址元素鏈接地址1000Ha1010H1004Hb100CH1008Hc1000H100CHdNULL1010He1004H1014H現將f存放于1014H處并插入到單鏈表中&#xff0c;若f在邏輯上位于a和e之間&#xff0c;則a, e, f的“鏈接地址”依次是&#xff08; &…

雙線串行的 “跨界對話”:I2C 與 MDIO 的異同解析

在電子系統設計中,串行總線憑借其精簡的信號線數量和靈活的拓撲結構,成為芯片間通信的主流選擇。I2C(Inter-Integrated Circuit)和 MDIO(Management Data Input/Output)作為兩種典型的雙線串行總線,雖同屬低速信號范疇,卻在各自的應用領域扮演著不可替代的角色。本文將…

算法精講:二分查找(二)—— 變形技巧

&#x1f3af; 算法精講&#xff1a;二分查找&#xff08;二&#xff09;—— 變形技巧 &#x1f50d; 友情提示&#xff1a;&#xff1a;本小節含高能代碼片段 &#x1f964; 閱讀前請確保已掌握基礎二分原理與實現代碼片段可能包含不同程度的變形&#xff0c;請根據實際情況選…

兩個程序配合實現了基于共享內存和信號量的進程間通信,具體說明如下:

第一個程序&#xff1a;共享內存讀取程序&#xff08;消費者&#xff09;該程序作為消費者&#xff0c;從共享內存中讀取數據&#xff0c;通過信號量保證只有當生產者寫入數據后才能讀取。/*4 - 讀共享內存*/ #include<stdio.h> // 標準輸入輸出庫 #inc…

JeecgBoot(1):前后臺環境搭建

1 項目介紹 JeecgBoot 是一款基于 Java 的 AI 低代碼平臺&#xff0c;它采用了 SpringBoot、SpringCloud、Ant Design Vue3、Mybatis 等技術棧&#xff0c;并集成了代碼生成器、AI 對話助手、AI 建表、AI 寫文章等功能。JeecgBoot 的設計宗旨是實現簡單功能零代碼開發&#xf…

Nestjs框架: 關于 OOP / FP / FRP 編程

概述 在軟件開發過程中&#xff0c;不同的編程范式為我們提供了多樣化的思維方式與實現路徑它們不僅影響著代碼的結構和邏輯組織方式&#xff0c;也深刻影響著項目的可維護性、可擴展性以及團隊協作效率 什么是 OOP、FP 和 FRP&#xff1f;首先從三個術語的含義入手 1 &#xf…

elememtor 添加分頁功能

各位看官好&#xff0c;最近在忙著使用elementor搭建自己的網站&#xff0c;由于我不是專業的程序員和前端&#xff0c;又沒有很多錢去找外包公司實現自己的設計&#xff0c;所以選擇了elementor. 總的來說這是一個不錯的wordpress 插件&#xff0c;也讓我們這種非專業的網站設…

關于“PromptPilot” 之2 -目標系統:Prompt構造器

目標系統&#xff1a;Prompt構造器想法首先&#xff0c;在抽象層對PromptPilot進行封裝給出提示詞形成過程的全部環節。然后&#xff0c;在 形成一套確定的提示詞后再為 小規模試點方案生成一整套開發工具并配套集成開發環境和指南。最后&#xff0c;在小規模試點成功后進行拓展…

短劇小程序系統開發:重塑影視內容消費格局

在數字化浪潮的推動下&#xff0c;影視內容消費正經歷著深刻的變革。短劇小程序系統開發作為這一變革的重要力量&#xff0c;正在重塑影視內容消費的格局&#xff0c;為用戶帶來更加個性化、便捷化的觀影體驗。傳統影視內容消費往往受到時間和空間的限制&#xff0c;用戶需要前…

一文掌握最新版本Monocle3單細胞軌跡(擬時序)分析

許多大佬的軟件想要構建一個大而美的生態&#xff0c;從 monocle2 開始就能做單細胞的質控、降維、分群、注釋這一系列的分析&#xff0c;但不幸的是我們只知道 monocle 系列還是主要做擬時序分析&#xff0c;一方面是因為 Seurat 有先發優勢&#xff0c;出名要趁早&#xff0c…

spark入門-helloword

我們學習編程語言的時候&#xff0c;第一個程序就是打印一下 “hello world” &#xff0c;對于大數據領域的第一個任務則是wordcount。那我們就開始我們的第一個spark任務吧&#xff01; 下載spark 官方下載地址&#xff1a;Apache Download Mirrors 下載完畢以后&#xff0c…

雷達系統設計學習:自制6GHz FMCW Radar

國外大神自制6GHZ FMCW Radar開源項目: https://github.com/Ttl/fmcw3 引言 之前我做過一個簡單的調頻連續波&#xff08;FMCW&#xff09;雷達&#xff0c;能夠探測到100米范圍內人體大小的物體。雖然它確實能用&#xff0c;但由于預算有限&#xff0c;還有很大的改進空間。 …

系統選擇菜單(ubuntu grub)介紹

好的&#xff0c;我們來詳細解釋一下什么是Ubuntu的GRUB菜單。 簡單來說&#xff0c;GRUB菜單是您電腦啟動時看到的第一個交互界面&#xff0c;它就像一個“系統選擇”菜單&#xff0c;讓您決定接下來要啟動哪個操作系統或進入哪種模式。詳細解釋 1. GRUB是什么&#xff1f; GR…

方案C,version2

實現一個簡單的Helloworld網頁,并通過GitHub Actions自動構建并推送到公開倉庫的gh-pages分支。同時,使用PAT進行認證,確保源碼在私有倉庫中,構建后的靜態文件在公開倉庫中。 重新設計deploy.yml內容如下(針對純靜態文件,無需構建過程): 步驟: 檢出私有倉庫源碼。 由于…

R 語言科研繪圖 --- 其他繪圖-匯總1

在發表科研論文的過程中&#xff0c;科研繪圖是必不可少的&#xff0c;一張好看的圖形會是文章很大的加分項。 為了便于使用&#xff0c;本系列文章介紹的所有繪圖都已收錄到了 sciRplot 項目中&#xff0c;獲取方式&#xff1a; R 語言科研繪圖模板 --- sciRplothttps://mp.…

webpack 原理及使用

【點贊收藏加關注,前端技術不迷路~】 一、webpack基礎 1.核心概念 1)entry:定義入口,webpack構建的第一步 module.exports ={entry:./src/xxx.js } 2)output:出口(輸出) 3)loader:模塊加載器,用戶將模塊的原內容按照需求加載成新內容 比如文本加載器raw-loade…

「日拱一碼」039 機器學習-訓練時間VS精確度

目錄 時間-精度權衡曲線&#xff08;不同模型復雜度&#xff09; 訓練與驗證損失對比 帕累托前沿分析&#xff08;3D&#xff09; 在機器學習實踐中&#xff0c;理解模型收斂所需時間及其與精度的關系至關重要。下面介紹如何分析模型收斂時間與精度之間的權衡&#xff0c;并…

面試刷題平臺項目總結

項目簡介&#xff1a; 面試刷題平臺是一款基于 Spring Boot Redis MySQL Elasticsearch 的 面試刷題平臺&#xff0c;運用 Druid HotKey Sa-Token Sentinel 提高了系統的性能和安全性。 第一階段&#xff0c;開發基礎的刷題平臺&#xff0c;帶大家熟悉項目開發流程&#xff…