【基礎算法】初識搜索:遞歸型枚舉與回溯剪枝

文章目錄

  • 一、搜索
    • 1. 什么是搜索?
    • 2. 遍歷 vs 搜索
    • 3. 回溯與剪枝
  • 二、OJ 練習
    • 1. 枚舉子集 ?
      • (1) 解題思路
      • (2) 代碼實現
    • 2. 組合型枚舉 ?
      • (1) 解題思路
    • 請添加圖片描述
      • (2) 代碼實現
    • 3. 枚舉排列 ?
      • (1) 解題思路
      • (2) 代碼實現
    • 4. 全排列問題 ?
      • (1) 解題思路
      • (2) 代碼實現

一、搜索

1. 什么是搜索?

搜索,是一種枚舉,通過窮舉所有的情況來找到最優解,或者統計合法解的個數。因此,搜索有時候也叫作暴搜。 搜索一般分為深度優先搜索 (DFS) 與寬度優先搜索 (BFS) 。

2. 遍歷 vs 搜索

深度優先遍歷 vs 深度優先搜索,寬度優先遍歷 vs 寬度優先搜索?遍歷是形式,搜索是目的。 不過,在一般情況下,我們不會去糾結概念的差異,兩者可以等同。

3. 回溯與剪枝

回溯:當在搜索的過程中,遇到走不通或者走到底的情況時,就回頭。

剪枝:剪掉在搜索過程中,重復出現或者不是最優解的分支。


二、OJ 練習

1. 枚舉子集 ?

【題目鏈接】

B3622 枚舉子集(遞歸實現指數型枚舉) - 洛谷

【題目描述】

今有 nnn 位同學,可以從中選出任意名同學參加合唱。

請輸出所有可能的選擇方案。

【輸入格式】

僅一行,一個正整數 nnn

【輸出格式】

若干行,每行表示一個選擇方案。

每一種選擇方案用一個字符串表示,其中第 iii 位為 Y 則表示第 iii 名同學參加合唱;為 N 則表示不參加。

需要以字典序輸出答案。

【示例一】

輸入

3

輸出

NNN
NNY
NYN
NYY
YNN
YNY
YYN
YYY

【說明/提示】

對于 100%100\%100% 的數據,保證 1≤n≤101\leq n\leq 101n10


(1) 解題思路

對于題目中給的示例來說,我們一共有 3 個人,也就是說我們有三個字母需要填,那么對于每一個字母都有兩種情況,我們不妨畫出一個樹狀圖來展示枚舉的過程。

請添加圖片描述

這樣的一棵樹狀圖又可以被稱為決策樹,它能夠很好的幫助我們枚舉出最后的答案,我們想要獲取答案實質上就是對這一棵樹進行一次深度優先遍歷 (DFS) 。

接下來我們只需要模擬一遍這個決策樹的過程即可。怎么模擬?首先,我們肯定是需要用到遞歸函數的,那么遞歸函數內部該如何設計?這就要看我們的決策樹了。函數體的主體部分就是在模擬決策樹的每一層都干了些什么,結束條件就是到葉子節點的時候。


(2) 代碼實現

#include<iostream>using namespace std;string path;  // 記錄遞歸過程中,每一步的決策
int n;void dfs()
{if(path.size() == n)  // 如果大小為n了說明到葉子節點了,需要輸出{cout << path << endl;return;}// 不選path += 'N';dfs();  // 遞歸到決策樹下一層// 到這里就已經重新回到上一層了,這個時候 path 內的最后一個位置還保留了下面層的數據,需要清除掉path.pop_back();  // 回溯,恢復現場// 選path += 'Y';dfs();  // 遞歸到下一層path.pop_back();  // 回溯,恢復現場
}int main()
{cin >> n;dfs();return 0;
}

2. 組合型枚舉 ?

P10448 組合型枚舉 - 洛谷

【題目描述】

1~n1 \sim n1nnnn 個整數中隨機選出 mmm 個,輸出所有可能的選擇方案。

【輸入格式】

兩個整數 n,mn, mn,m ,在同一行用空格隔開。

【輸出格式】

按照從小到大的順序輸出所有方案,每行 111 個。

首先,同一行內的數升序排列,相鄰兩個數用一個空格隔開。

其次,對于兩個不同的行,對應下標的數一一比較,字典序較小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。

【示例一】

輸入

5 3

輸出

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5

【說明/提示】

對于所有測試數據滿足 0≤m≤n0 \le m \le n0mn , $ n+(n-m) \le 25 $。


(1) 解題思路

首先畫出決策樹:

注意到在這道題中,由于我們需要枚舉的是升序的序列,每一層枚舉的時候是從前一個位置數字的下一個數字開始枚舉的,因此在 dfs() 函數中,我們需要知道當前層我們應該從哪里開始枚舉

請添加圖片描述

(2) 代碼實現

#include<iostream>
#include<vector>using namespace std;vector<int> path;  // 記錄遞歸過程
int n, m;// 從 begin 位置開始往后枚舉
void dfs(int begin)
{if(path.size() == m)  // 結束條件{for(auto e : path) cout << e << " ";cout << endl;return;}for(int i = begin; i <= n; i++){path.push_back(i); dfs(i + 1);  // 下一層就從當前位置填的這個數的下一個數開始枚舉path.pop_back();  // 恢復現場}
}int main()
{cin >> n >> m;dfs(1);return 0;
}

3. 枚舉排列 ?

【題目鏈接】

B3623 枚舉排列(遞歸實現排列型枚舉) - 洛谷

【題目描述】

今有 nnn 名學生,要從中選出 kkk 人排成一列拍照。

請按字典序輸出所有可能的排列方式。

【輸入格式】

僅一行,兩個正整數 n,kn, kn,k

【輸出格式】

若干行,每行 kkk 個正整數,表示一種可能的隊伍順序。

【示例一】

輸入

3 2

輸出

1 2
1 3
2 1
2 3
3 1
3 2

【說明/提示】

對于 100%100\%100% 的數據,1≤k≤n≤101\leq k\leq n \leq 101kn10


(1) 解題思路

首先畫出決策樹:

遞歸函數主體部分的邏輯就是在枚舉 1, 2, 3 這三個數,所以我們只需要寫一個 for 循環枚舉 1 ~ n 即可。重點是我們不能選擇已經選過的數字,也就是說我們需要剪枝。如何實現剪枝呢?我們可以搞一個 vis 數組,它的第 i 個位置代表 i 這個數有沒有被選擇過,在我們枚舉的過程中只需要在 vis 數組中看一下當前位置的是否被選擇過即可,如果被選擇過那么 continue,否則請添加圖片描述
就正常執行。


(2) 代碼實現

#include<iostream>
#include<vector>using namespace std;const int N = 15;vector<int> path;
bool vis[N];  // 標記哪些數已經被選擇了
int n, m;void dfs()
{if(path.size() == m){for(auto e : path) cout << e << " ";cout << endl;return;}for(int i = 1; i <= n; i++){if(!vis[i])  // 如果當前數沒有被選擇{path.push_back(i);vis[i] = true;  // 當前數被選擇了,需要在 vis 數組中標記一下dfs();  // 遞歸到下一層path.pop_back();  // 恢復現場vis[i] = false;  // 恢復現場}}
}int main()
{cin >> n >> m;dfs();return 0;
}

4. 全排列問題 ?

【題目鏈接】

P1706 全排列問題 - 洛谷

【題目描述】

按照字典序輸出自然數 111nnn 所有不重復的排列,即 nnn 的全排列,要求所產生的任一數字序列中不允許出現重復的數字。

【輸入格式】

一個整數 nnn

【輸出格式】

1~n1 \sim n1n 組成的所有不重復的數字序列,每行一個序列。

每個數字保留 555 個場寬。

【示例一】

輸入

3

輸出

	1    2    31    3    22    1    32    3    13    1    23    2    1

【說明/提示】

1≤n≤91 \leq n \leq 91n9


(1) 解題思路

首先畫出決策樹:

解法同【枚舉排列】,唯一不同的是遞歸出口不同。


(2) 代碼實現

請添加圖片描述

#include<iostream>
#include<vector>using namespace std;const int N = 10;int n;
vector<int> path;
bool vis[N];void dfs()
{if(path.size() == n){for(auto e : path) cout << "    " << e;cout << endl;return;}for(int i = 1; i <= n; i++){if(!vis[i])  // 如果當前數沒有被選擇{path.push_back(i);vis[i] = true;dfs();  // 遞歸到下一層path.pop_back();  // 恢復現場vis[i] = false;  // 恢復現場}}
}int main()
{cin >> n;dfs();return 0;
}

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

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

相關文章

Node.js異步編程——async/await實現

一、async/await基礎語法 在Node.Js編程中,async關鍵字用于定義異步函數,這個異步函數執行完會返回一個Promise對象,異步函數的內部可以使用await關鍵字來暫停當前代碼的繼續執行,直到Promise操作完成。 在用法上,async關鍵字主要用于聲明一個異步函數,await關鍵字主要…

搭建一個簡單的Agent

準備本案例使用deepseek&#xff0c;登錄deepseek官網&#xff0c;登錄賬號&#xff0c;充值幾塊錢&#xff0c;然后創建Api key可以創建虛擬環境&#xff0c;python版本最好是3.12&#xff0c;以下是文件目錄。test文件夾中&#xff0c;放一些txt文件做測試&#xff0c;main.p…

uv,下一代Python包管理工具

什么是uv uv&#xff08;Universal Virtual&#xff09;是由Astral團隊&#xff08;知名Python工具Ruff的開發者&#xff09;推出的下一代Python包管理工具&#xff0c;使用Rust編寫。它集成了包管理、虛擬環境、依賴解析、Python版本控制等功能&#xff0c;它聚焦于三個關鍵點…

單片機的輸出模式推挽和開漏如何選擇呢?

推挽和開漏是單片機的輸出模式&#xff0c;屬于I/O口配置的常見類型。開漏&#xff08;Open-Drain&#xff09;和推挽&#xff08;Push-Pull&#xff09;是兩種根本不同的輸出電路結構&#xff0c;理解它們的區別是正確使用任何單片機&#xff08;包括51和STM32&#xff09;GPI…

java18學習筆記-Simple Web Server

408:Simple Web Server Python、Ruby、PHP、Erlang 和許多其他平臺提供從命令行運行的開箱即用服務器。這種現有的替代方案表明了對此類工具的公認需求。 提供一個命令行工具來啟動僅提供靜態文件的最小web服務器。沒有CGI或類似servlet的功能可用。該工具將用于原型設計、即…

深度解析Atlassian 團隊協作套件(Jira、Confluence、Loom、Rovo)如何賦能全球分布式團隊協作

無窮無盡的聊天記錄、混亂不堪的文檔、反饋信息分散在各個不同時區……在全球分布式團隊中開展真正的高效協作&#xff0c;就像是一場不可能完成的任務。 為什么會這樣&#xff1f;因為即使是最聰明的團隊&#xff0c;也會遇到類似的障礙&#xff1a; 割裂的工作流&#xff1a…

理解AI 智能體:智能體架構

1. 引言 智能體架構&#xff08;agent architecture&#xff09;是一份藍圖&#xff0c;它定義了AI智能體各組件的組織方式和交互機制&#xff0c;使智能體能夠感知環境、進行推理并采取行動。本質上&#xff0c;它就像是智能體的數字大腦——整合了“眼睛”&#xff08;傳感器…

Spring Cloud系列—SkyWalking鏈路追蹤

上篇文章&#xff1a; Spring Cloud系列—Seata分布式事務解決方案TCC模式和Saga模式https://blog.csdn.net/sniper_fandc/article/details/149947829?fromshareblogdetail&sharetypeblogdetail&sharerId149947829&sharereferPC&sharesourcesniper_fandc&…

機器人領域的算法研發

研究生期間學習大模型&#xff0c;可投遞機器人領域的算法研發、技術支持等相關崗位&#xff0c;以下是具體推薦&#xff1a; AI算法工程師&#xff08;大模型方向-機器人應用&#xff09;&#xff1a;主要負責大模型開發與優化&#xff0c;如模型預訓練、調優及訓練效率提升等…

深度學習入門:神經網絡

文章目錄一、深度學習基礎認知二、神經網絡核心構造解析2.1 神經元的基本原理2.2 感知器&#xff1a;最簡單的神經網絡2.3 多層感知器&#xff1a;引入隱藏層解決非線性問題2.3.1 多層感知器的結構特點2.3.2 偏置節點的作用2.3.3 多層感知器的計算過程三、神經網絡訓練核心方法…

mysql的索引有哪些?

1. 主鍵索引&#xff08;PRIMARY KEY&#xff09;主鍵索引通常在創建表時定義&#xff0c;確保字段唯一且非空&#xff1a;-- 建表時直接定義主鍵 CREATE TABLE users (id INT NOT NULL,name VARCHAR(50),PRIMARY KEY (id) -- 單字段主鍵 );-- 復合主鍵&#xff08;多字段組合…

【計算機視覺與深度學習實戰】08基于DCT、DFT和DWT的圖像變換處理系統設計與實現(有完整代碼python3.13可直接粘貼使用)

1. 引言 數字圖像處理作為計算機視覺和信號處理領域的重要分支,在過去幾十年中得到了快速發展。圖像變換技術作為數字圖像處理的核心技術之一,為圖像壓縮、特征提取、去噪和增強等應用提供了強有力的數學工具。離散余弦變換(Discrete Cosine Transform, DCT)、離散傅里葉變…

使用Python實現DLT645-2007智能電表協議

文章目錄&#x1f334;通訊支持&#x1f334; 功能完成情況服務端架構設計一、核心模塊劃分二、數據層定義三、協議解析層四、通信業務層&#xff08;以DLT645服務端為例&#xff09;五、通信層&#xff08;以TCP為例&#xff09;使用例子&#x1f334;通訊支持 功能狀態TCP客…

未來已來:基于IPv6單棧隔離架構的安全互聯實踐報告

未來已來&#xff1a;基于IPv6單棧隔離架構的安全互聯實踐報告 報告摘要 隨著IPv4地址資源徹底枯竭&#xff0c;全球網絡基礎設施正加速向IPv6單棧&#xff08;IPv6-Only&#xff09;演進。傳統“IPv4為主、IPv6為輔”的雙棧模式已無法滿足數字化轉型對海量地址、端到端連接與原…

Ubuntu24.04 安裝 Zabbix

Ubuntu24.04 安裝 Zabbix 環境&#xff1a; 軟件版本Ubuntu24.04.3Nginx1.24.0MySQL8.4.6PHP8.3.6phpMyAdmin5.2.2Zabbix7.4.1 LNMP 1. 更新本地軟件包索引并升級已安裝軟件 更新可用軟件包列表 把已安裝的軟件升級到最新版 安裝常用工具 sudo apt update && sud…

【動手學深度學習】6.2. 圖像卷積

目錄6.2. 圖像卷積1&#xff09;互相關運算2&#xff09;卷積層3&#xff09;圖像中目標的邊緣檢測4&#xff09;學習卷積核5&#xff09;互相關與卷積6&#xff09;特征映射和感受野7&#xff09;小結. 6.2. 圖像卷積 卷積神經網絡的設計是用于探索圖像數據&#xff0c;本節…

游戲引擎中的Billboard技術

一.視覺公告板為解決場景中Mesh網格面數過多問題,使用2D平面Mesh替換為3D平面Mesh的技術即為Billboard技術.常用于場景中植被,樹葉,粒子系統等對面數有要求的場景.二.Billboard著色器實現著色器輸入參數:攝像機坐標,網格坐標,攝像機觀察方向著色器輸出:實際2D平面隨視角不變

vue-admin-template權限管理

在基于 vue-admin-template 實現權限管理時&#xff0c;通常需要結合角色權限模型和動態路由機制&#xff0c;以滿足不同用戶角色對頁面訪問權限的控制需求。分為路由頁面權限和按鈕權限&#xff1a;下面是具體實現思路的思維導圖和具體代碼流程&#xff1a;0.實現邏輯思維導圖…

微信小程序,事件總線(Event Bus) 實現

1、util.js文件/*** 事件總線*/ function createEventBus() {// 私有事件存儲對象&#xff0c;通過閉包保持私有性const events {};return {/*** 監聽事件&#xff0c;只執行一次* param {string} eventName - 事件名稱* param {Function} callback - 回調函數*/once(eventNam…

OpenCV結構光三維重建類cv::structured_light::GrayCodePattern

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 cv::structured_light::GrayCodePattern 是 OpenCV 庫中用于結構光三維重建 的一個類&#xff0c;屬于 OpenCV 的 structured_light 模塊。 它用于…