【遞歸與動態規劃(DP) C/C++】(1)遞歸 與 動態規劃(DP)

- 第 82 篇 -
Date: 2025 - 03 - 17
Author: 鄭龍浩/仟濹
【遞歸與動態規劃(DP) C/C++】

文章目錄

  • 一 遞歸
    • 1基本介紹
    • 2 遞歸技巧
      • **(1) 遞歸三步法**
      • **(2) 思維小技巧**
    • 3 例題
      • (1) 階乘 (純遞歸 or DP)
      • (2) 斐波那契數列 (純遞歸 or DP)
      • (3) 漢諾塔 (純遞歸 or DP)
        • **① 英文打印過程的版本**
        • **② 中文打印過程的版本(為了避免自己以后復習的時候又理解錯誤,故寫了中文打印版本)**

一 遞歸

我看的課程,如下視頻鏈接

https://www.bilibili.com/video/BV1LiS1YSEgF/?share_source=copy_web&vd_source=123565abb60ee9d849adaeb118d98b85

1基本介紹

是什么

遞歸就是函數自己調用自己。

核心

將大問題分解成規模更小的相同問題,直到達到可直接求解的簡單情況(如 n=1),再逐層返回結果。
優化 - 記憶化搜索

如果過程中會出現重復計算,則可以提前將重復計算保存下來

2 遞歸技巧

(1) 遞歸三步法

  1. 定義基準條件(確定結束條件)

    明確遞歸終止的邊界條件(如 階乘時的n=1 ),避免無限遞歸

  2. 假設子問題已解決
    將遞歸函數視為黑盒,直接假設它能返回子問題的正確結果(例如:算 f(n) 時,直接相信 f(n-1)f(n-2) 是對的)

    說簡單點就是: 只管向問問題,它一定能返回正確答案。

  3. 組合子問題的解(拆解問題)

    用子問題的解構建當前問題的解(如 return f(n-1) + f(n-2)

    說簡單點就是: 把子問題的答案組合起來,得到當前問題的解

(2) 思維小技巧

無需提前理解完整遞歸過程!!!

我之前就陷入了這個問題。就是我在寫遞歸的時候,必須想清楚遞歸從頭到尾的所有過程和細節,其實沒有必要,直接當作這個遞歸函數已經存在且寫完

遞歸是「自相似性」的數學抽象,只需關注當前層邏輯,無需腦補調用棧細節(如 f(n-1) 內部如何實現)

不要陷入 “先有雞還是先有蛋“ 的思維陷阱!!!

一定要注意,我之前因為陷入這個思維陷阱,特別較真,特別想搞清楚具體過程,太沒必要了

  • 直接假設遞歸函數已能正確工作(即使它尚未寫完),基于此設計當前邏輯。這種「信任遞歸」的思維是突破遞歸障礙的關鍵
  • 即直接將沒寫完的遞歸函數當作已經有了的函數去寫,就認為這個函數是有答案的,這么去寫就可以了,無需把這個遞歸函數中的自身的函數當作遞歸函數
  • 禁止:在編碼時腦補多級遞歸調用的堆棧狀態

3 例題

(1) 階乘 (純遞歸 or DP)

不使用記憶化搜索 Or 使用記憶化搜索

// 2025-03-16
#include <bits/stdc++.h>
using namespace std;
// 不使用記憶化搜索
long long funA( long long n ) {if (n == 1)return 1;return funA(n - 1) * n;
}
// 使用記憶化搜索
// 使用數組或哈希表記憶
unordered_map <long long, long long> memo;
long long funB( long long n ) {if (n == 1)return 1;if (memo.find(n) == memo.end()) {memo[n] = funB(n - 1) * n;}return memo[n];
}int main( void ) {long long n;cin >> n;// 不使用記憶化搜索cout << "不使用記憶化搜索的答案:" << funA(n) << '\n';// 使用記憶化搜索cout << "使用記憶化搜索的答案:" << funB(n) << '\n';return 0;
}

(2) 斐波那契數列 (純遞歸 or DP)

不使用記憶化搜索 Or 使用記憶化搜索

// 2025-03-16
#include <bits/stdc++.h>
using namespace std;
// 不使用記憶化搜索
long long funA( long long n ) {if (n <= 2) return 1;return funA(n - 1) + funA(n - 2);
}
// 使用記憶化搜索
// 使用數組或哈希表記憶
unordered_map <long long, long long> memo;
long long funB( long long n ) {if (n <= 2) return 1;if (memo.find(n) == memo.end())memo[n] = funB(n - 1) + funB(n - 2);return memo[n];
}int main( void ) {// 第n位斐波那契數字long long n;cin >> n;// 不使用記憶化搜索cout << "不使用記憶化搜索的答案:" << funA(n) << '\n';// 使用記憶化搜索cout << "使用記憶化搜索的答案:  " << funB(n) << '\n';return 0;
}

(3) 漢諾塔 (純遞歸 or DP)

必須要注意,打印的不是 前 n 個 圓盤從某個柱子移動到某個柱子,而是 第 n 個 圓盤從某個柱子移動到某個柱子。

我剛開始想了好久,就是這個地方理解錯了,我以為打印的是 前 n 個 圓盤,后來意識到是 第 n 個 圓盤以后,恍然大悟,理解了這個程序。

然后為了助于我理解,我又寫了一個中文打印過程版本,以免以后復習的時候,看到這個英文打印的代碼又理解錯了。

① 英文打印過程的版本

代碼

// 2025-03-16
// 輸入圓盤數量,三個柱子標識
// 打印圓盤的移動過程: 移動數量 from ? to ? ---> 錯誤理解
// 打印圓盤的移動過程: 第n個 from ? to ? (這個意思是第 n 個 從 ? 移動到 ?) --> 正確理解
// 注意:該題要求的是移動過程的輸出,而不是真的移動,所以不要鉆牛角尖,我想了半天為什么只打印不移動,實際人家要的結果就是打印
#include <bits/stdc++.h>
using namespace std;
void hanoi(int n, char F, char A, char T) {if (n == 1) { // 遞歸終止條件:只剩一個盤子時直接移動// 打印:move 1 from A to C// 打印:移動第 n 個盤子到目標柱 Tprintf("move %d from %c to %c\n", n, F, T);return;}// 步驟1:將前 n-1 個盤子從 F 移到 A(借助 T 輔助)hanoi(n - 1, F, T, A); // 步驟2:打印:移動第 n 個盤子到目標柱 Tprintf("move %d from %c to %c\n", n, F, T);// 步驟3:將 n-1 個盤子從 A 移到 T(借助 F 輔助)hanoi(n - 1, A, F, T);
}
int main( void ) {int n, F, A, T;cout << "請輸入圓盤數量" << endl;cin >> n;getchar();cout << "請輸入起始柱、輔助柱、目標柱" << endl;scanf ("%c %c %c", &F, &A, &T);hanoi (n, F, A, T);return 0;
}

輸入與運行結果

請輸入圓盤數量
3
請輸入起始柱、輔助柱、目標柱
A B C
move 1 from A to C
move 2 from A to B
move 1 from C to B
move 3 from A to C
move 1 from B to A
move 2 from B to C
move 1 from A to C
② 中文打印過程的版本(為了避免自己以后復習的時候又理解錯誤,故寫了中文打印版本)

為了避免自己以后復習的時候又理解錯誤,故寫了中文打印版本

代碼

// 2025-03-16
// 輸入圓盤數量,三個柱子標識
// 打印圓盤的移動過程: 移動數量 from ? to ? ---> 錯誤理解
// 打印圓盤的移動過程: 第n個 from ? to ? (這個意思是第 n 個 從 ? 移動到 ?) --> 正確理解
// 注意:該題要求的是移動過程的輸出,而不是真的移動,所以不要鉆牛角尖,我想了半天為什么只打印不移動,實際人家要的結果就是打印
#include <bits/stdc++.h>
using namespace std;
void hanoi(int n, char F, char A, char T) {if (n == 1) { // 遞歸終止條件:只剩一個盤子時直接移動// 打印:move 1 from A to C// 打印:移動第 n 個盤子到目標柱 Tprintf("將第 %d 個圓盤從 %c 柱子移動到 %c 柱子\n", n, F, T);return;}// 步驟1:將前 n-1 個盤子從 F 移到 A(借助 T 輔助)hanoi(n - 1, F, T, A); // 步驟2:打印:移動第 n 個盤子到目標柱 Tprintf("將第 %d 個圓盤從 %c 柱子移動到 %c 柱子\n", n, F, T);// 步驟3:將 n-1 個盤子從 A 移到 T(借助 F 輔助)hanoi(n - 1, A, F, T);
}
int main( void ) {int n, F, A, T;cout << "請輸入圓盤數量" << endl;cin >> n;getchar();cout << "請輸入起始柱、輔助柱、目標柱" << endl;scanf ("%c %c %c", &F, &A, &T);hanoi (n, F, A, T);return 0;
}

輸入與運行結果

請輸入圓盤數量
3
請輸入起始柱、輔助柱、目標柱
A B C
將第 1 個圓盤從 A 柱子移動到 C 柱子
將第 2 個圓盤從 A 柱子移動到 B 柱子      
將第 1 個圓盤從 C 柱子移動到 B 柱子      
將第 3 個圓盤從 A 柱子移動到 C 柱子      
將第 1 個圓盤從 B 柱子移動到 A 柱子      
將第 2 個圓盤從 B 柱子移動到 C 柱子      
將第 1 個圓盤從 A 柱子移動到 C 柱子

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

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

相關文章

eclipse運行配置,希望帶參數該怎么配置

java -Dparam 在eclipse如何配置 在Eclipse中配置-Dparam這樣的JVM參數&#xff0c;你可以按照以下步驟進行&#xff1a; 打開Eclipse。 選擇菜單欄的"Run" -> "Run Configurations..."。 在彈出的"Run Configurations"窗口左側&#xff0…

什么是 Fisher 信息矩陣

什么是 Fisher 信息矩陣 Fisher 信息矩陣是統計學和機器學習中一個重要的概念,它用于衡量樣本數據所包含的關于模型參數的信息量。 伯努利分布示例 問題描述 假設我們有一個服從伯努利分布的隨機變量 X X X,其概率質量函數為 P ( X 

[C++面試] 標準容器面試點

一、入門 1、vector和list的區別 [C面試] vector 面試點總結 vector 是動態數組&#xff0c;它將元素存儲在連續的內存空間中。支持隨機訪問&#xff0c;即可以通過下標快速訪問任意位置的元素&#xff0c;時間復雜度為 O(1)&#xff0c;準確點是均攤O(1)。但在中間或開頭插…

C++抽象與類的核心概念解析

在C中&#xff0c;抽象&#xff08;Abstraction&#xff09; 是面向對象編程&#xff08;OOP&#xff09;的核心概念之一&#xff0c;它通過隱藏復雜的實現細節&#xff0c;僅暴露必要的接口來實現對現實世界的簡化建模。類&#xff08;Class&#xff09; 是實現抽象的核心工具…

C# NX二次開發:拉伸UFUN函數避坑指南

大家好&#xff0c;今天想說一下拉伸相關UFUN函數的使用&#xff0c;盡量讓大家別踩坑。 官方給出的拉伸UFUN函數有如下幾個&#xff1a; &#xff08;1&#xff09;UF_MODL_create_extruded2 (view source) uf_list_p_tobjectsInputList of objects to be extruded.char *ta…

基于 Python 爬取 TikTok 搜索數據 Tiktok爬蟲(2025.3.17)

1. 前言 在數據分析和網絡爬蟲的應用場景中&#xff0c;我們經常需要獲取社交媒體平臺的數據&#xff0c;例如 TikTok。本篇文章介紹如何使用 Python 爬取 TikTok 用戶搜索數據&#xff0c;并解析其返回的數據。 結果截圖 2. 項目環境準備 在正式運行代碼之前&#xff0c;我…

AI日報 - 2025年3月18日

AI日報 - 2025年3月18日 &#x1f31f; 今日概覽&#xff08;60秒速覽&#xff09; ▎&#x1f916; AGI突破 | SOO微調技術減少語言模型欺騙行為10倍 創新對齊技術為更安全AI鋪路 ▎&#x1f4bc; 商業動向 | Figure推出全球最高產量人形機器人生產線BotQ 年產1.2萬臺&#x…

【go】函數類型的作用

Go 語言函數類型的巧妙應用 函數類型在 Go 語言中非常強大&#xff0c;允許將函數作為值進行傳遞和操作。下面詳細介紹函數類型的各種妙用&#xff1a; 1. 回調函數 // 定義一個函數類型 type Callback func(int) int// 接受回調函數的函數 func processData(data []int, ca…

每日一題--進程與協程的區別

進程是什么&#xff1f; 進程&#xff08;Process&#xff09; 是操作系統進行 資源分配和調度的基本單位&#xff0c;代表一個正在執行的程序實例。每個進程擁有獨立的虛擬地址空間、代碼、數據和系統資源&#xff08;如文件句柄、網絡端口等&#xff09;。進程之間通過 IPC&…

關于deepseek R1模型分布式推理效率分析

1、引言 DeepSeek R1 采用了混合專家&#xff08;Mixture of Experts&#xff0c;MoE&#xff09;架構&#xff0c;包含多個專家子網絡&#xff0c;并通過一個門控機制動態地激活最相關的專家來處理特定的任務 。DeepSeek R1 總共有 6710 億個參數&#xff0c;但在每個前向傳播…

二叉樹算法題實戰:從遍歷到子樹判斷

目錄 一、引言 二、判斷兩棵二叉樹是否相同 思路 代碼實現 注意點 三、二叉樹的中序遍歷 思路 代碼實現 注意點 四、判斷一棵樹是否為另一棵樹的子樹 思路 代碼實現 注意點 ?編輯 五、補充 一、引言 作者主頁&#xff1a;共享家9527-CSDN博客 作者代碼倉庫&am…

【開原寶藏】30天學會CSS - DAY1 第一課

下面提供一個由淺入深、按步驟拆解的示例教程&#xff0c;讓你能從零開始&#xff0c;逐步理解并實現帶有旋轉及懸停動畫的社交圖標效果。為了更簡單明了&#xff0c;以下示例僅創建四個圖標&#xff08;Facebook、Twitter、Google、LinkedIn&#xff09;&#xff0c;并在每一步…

HarmonyOS第22天:解鎖鴻蒙服務開發

走進鴻蒙服務開發的世界 在移動應用開發的領域中&#xff0c;HarmonyOS 以其獨特的分布式理念和強大的系統能力&#xff0c;為開發者們開辟了一片嶄新的天地。其中&#xff0c;服務開發作為 HarmonyOS 應用開發的關鍵環節&#xff0c;猶如一把神奇的鑰匙&#xff0c;能夠幫助開…

鴻蒙應用程序包HAP的開發與使用

1、HAP是什么&#xff1f; HAP&#xff08;Harmony Ability Package&#xff09;是應用安裝和運行的基本單元。HAP包是由代碼、資源、第三方庫、配置文件等打包生成的模塊包&#xff0c;其主要分為兩種類型&#xff1a;entry和feature。 entry&#xff1a;應用的主模塊&#x…

解決qt中自定插件加載失敗,不顯示問題。

這個問題斷斷續續搞了一天多&#xff0c;主要是版本不匹配問題。 我們先來看下 Based on Qt 6.6.0 → 說明 Qt Creator 本身 是基于 Qt 6.6.0 框架構建的。MSVC 2019, 64-bit → 說明 Qt Creator 是使用 Microsoft Visual C 2019 編譯器&#xff08;64 位&#xff09; 編譯的。…

進程間通信--匿名管道

進程間通信介紹 進程間通信目的 數據傳輸&#xff1a;一個進程需要將它的數據發送給另一個進程資源共享&#xff1a;多個進程之間共享同樣的資源。通知事件&#xff1a;一個進程需要向另一個或一組進程發送消息&#xff0c;通知它&#xff08;它們&#xff09;發生了某種事件&…

vue computed 計算屬性簡述

Vue 的 ?計算屬性&#xff08;Computed Properties&#xff09;? 是 Vue 實例中一種特殊的屬性&#xff0c;用于?聲明式地定義依賴其他數據動態計算得出的值?。它的核心優勢在于能夠自動追蹤依賴關系&#xff0c;并緩存計算結果&#xff0c;避免重復計算&#xff0c;提升性…

CSS塊元素、行內元素、行內塊元素詳解

一、塊元素&#xff08;Block Elements&#xff09; 1.定義與特點 獨占一行&#xff1a;默認情況下&#xff0c;塊元素會從新的一行開始&#xff0c;并且其后的元素也會被推到下一行。可設置寬高&#xff1a;可以自由設置寬度&#xff08;width&#xff09;和高度&#xff08…

Vue3項目中可以嘗試封裝那些組件

在 Vue 3 項目中&#xff0c;組件的封裝可以根據功能、復用性和業務需求進行劃分。以下是一些常見的組件類型&#xff0c;適合封裝為獨立組件&#xff1a; 1. 基礎 UI 組件 按鈕 (Button) 封裝不同樣式、大小、狀態的按鈕。支持 disabled、loading 等狀態。 輸入框 (Input) 封…

2025年AI搜索引擎開源項目全景指南:從核心框架到生態工具

2025年AI搜索引擎開源項目全景指南&#xff1a;從核心框架到生態工具 在人工智能技術迅猛發展的當下&#xff0c;開源項目已成為構建AI搜索引擎的核心驅動力。本文整理9個具有代表性的開源項目&#xff0c;涵蓋搜索框架、擴展生態及底層支持技術&#xff0c;助你快速搭建或優化…