蓝桥杯C++深度优先搜索(dfs)之组队,迷宫,走方格
目錄
題目一:組隊(回溯法)
介紹:
題目:
?代碼(C++遞歸)
卡點①
卡點②?
題目二:迷宮
題目三:走方格?
這篇文章主要目的是借各種題目🍌學(xué)習(xí)深度優(yōu)先搜索🍌(depth-first search)
😄純新手0.o😊
題目一:組隊(回溯法)
介紹:
👹👹深度優(yōu)先搜索:
簡稱深搜或者👍爆搜(沒有什么是暴力解決不了的)
目的是遍歷,是無序的。過程是:
1、訪問頂點v
2、依次從v的未被訪問的鄰接點出發(fā),對圖進(jìn)行深度優(yōu)先遍歷;直至圖中所有和v有路徑相通的頂點被訪問💪
3、若此時圖中尚有頂點未被訪問,則從一個未被訪問的頂點出發(fā),重新進(jìn)行深度優(yōu)先遍歷,直到圖中所有頂點均被訪問過為止
看圖:
?路徑:
a? b? d? h? d? b? e? i? e? j? e? b? a? c? f? k? f? c? g(橙色表示初次經(jīng)過)
過程描述:
第一條路訪問了a,b,d,h,走到底了,就從h退回d,發(fā)現(xiàn)節(jié)點d沒有除h以外的沒訪問過的,就退回b,b有除d以外未訪問過的e,所以又從e開始進(jìn)行dfs...
被訪問的順序:
a --> b --> d --> h --> e --> i --> j --> c --> f --> k --> g
當(dāng)然初始是隨機(jī)的,它可以先從a到c,也可以先從a到b?
dfs一般找不到最優(yōu)解,所以它適合給了初始條件,尋找解但不要求找最優(yōu)解的題目
👹👹回溯法:
目的是求解過程,是有序的。回溯算法 =?樹的深度優(yōu)先搜索 + 剪枝函數(shù),是dfs的一種改進(jìn)
一般用遞歸實現(xiàn)
題目:
2019藍(lán)橋杯C/C++B組ヽ(?゚▽゚)ノ
作為籃球隊教練,你需要從以下名單中選出 1 號位至 5 號位各一名球員,
組成球隊的5人首發(fā)陣容。
每位球員擔(dān)任 1 號位至 5 號位時的評分如下表所示。請你計算首發(fā)陣容 1
號位至 5 號位的評分之和最大可能是多少?
?代碼(C++遞歸)
#include<iostream> #include<algorithm>//max() using namespace std;int a[20][6] = //聲明初始化二維數(shù)組存儲表格數(shù)據(jù) {{1,97,90,0,0,0},{2,92,85,96,0,0},{3,0,0,0,0,93},{4,0,0,0,80,86},{5,89,83,97,0,0},{6,82,86,0,0,0},{7,0,0,0,87,90},{8,0,97,96,0,0},{9,0,0,89,0,0},{10,95,99,0,0,0},{11,0,0,96,97,0},{12,0,0,0,93,98},{13,94,91,0,0,0},{14,0,83,87,0,0},{15,0,0,98,97,98},{16,0,0,0,93,86},{17,98,83,99,98,81},{18,93,87,92,96,98},{19,0,0,0,89,92},{20,0,99,96,95,81} };//因為是聲明二維數(shù)組,最后這里要加上";" int visit[20];//記錄20個隊員中誰被訪問過 int max_score = 0;//聲明全局變量max_score保存dfs函數(shù)里的最大值//index表示當(dāng)前位置, sum是當(dāng)前組合總分 void dfs(int index, int sum) {if(index == 6)//已經(jīng)選完5個人,可以比較總分了{(lán)max_score = max(max_score, sum);//第一次敲我漏了這個return;}for(int i = 0; i < 20; i++)//遍歷20個隊員{if(!visit[i])//如果他沒被訪問{visit[i] = 1;//已被訪問dfs(index+1, sum+a[i][index]);//在函數(shù)參數(shù)實現(xiàn)了累加visit[i] = 0;//繼續(xù)嘗試下一種5人組合}} }int main() {dfs(1,0);cout<<max_score<<endl;return 0; }輸出:? 490?
卡點①
代碼39~45行,for循環(huán)的遍歷中,dfs的遞歸,開始有點懵😫
so, 草稿紙上列出index, sum, i在第一種情況的大小?
| index | ? ? ? ? sum | ?i |
| 1 | ? ? ? ?a[0][1] | 0 |
| 2 | a[0][1]+a[1][2] | 1 |
| 3 | ? ... + a[2][3] | 2 |
| 4 | ? ... + a[3][4] | 3 |
| 5 | ? ... + a[4][5] | 4 |
index = 5時,就完成了5個隊員分?jǐn)?shù)的相加
卡點②?
代碼37行,if(index == 6)后的return;
不清楚index到了6后,是如何返回原來的值的
下面看解析:
先分析遞歸函數(shù)中的return ,看代碼👇👇
#include<iostream> using namespace std;int Sum(int n) {cout<<n<<" ";//讓大家看下遞歸累加順序if (n <= 1)//終止條件, 且Sum(1) == 1return n;return n+Sum(n - 1);//遞歸累加 }int main() {int n;while(cin>>n){int a = Sum(n);//累加和cout<<endl<<a<<endl;cout<<endl;} }輸入輸出
5 5 4 3 2 1 1510 10 9 8 7 6 5 4 3 2 1 5520 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 210分析
1,C++ 遞歸函數(shù)中的return是指:
從被調(diào)用函數(shù)返回到主調(diào)函數(shù)中繼續(xù)執(zhí)行,并非一遇到return整個遞歸結(jié)束
2,return 語句,顧名思義是終止當(dāng)前正在執(zhí)行的函數(shù)并將控制權(quán)返回到調(diào)用該函數(shù)的地方
3,在void的函數(shù)中也可以多次使用return,功能和循環(huán)中的break一樣,在中間位置提前退出正在執(zhí)行函數(shù),也就是回到原來位置執(zhí)行下一行代碼
4,return; 表示結(jié)束本次函數(shù)
5,?遞歸中的return常用來作為遞歸終止的條件,當(dāng)達(dá)到遞歸終止條件時,首先return的是最底層調(diào)用的函數(shù),return之后,繼續(xù)執(zhí)行上一層調(diào)用該函數(shù)之后的代碼?
在我對return進(jìn)行理解時,這篇文章給了我一定啟發(fā)關(guān)于遞歸中return的理解(最淺顯易懂)_Pledgee的博客-CSDN博客_遞歸函數(shù)return怎么理解
🔒首先1,2,3,4分別占據(jù)1,2,3,4位置,5號位置就可以依次讓隊員5-20占據(jù);然后4號位給5號隊員,又是一種新的情況,5號位可以依次給6-20號位占據(jù);依次這樣搜索,每個人都可以換個位置。
??其實就是一個排列組合問題,在20個人中選擇五個人,依次排列??
🔒所以說,index到了6后,返回原來遞歸位置的下一步,return到index=5,然后五號位 通過i ++,由5號隊員占據(jù),到6號占據(jù),一直到20號,接著return到四號位index=4,i++使5號隊員占據(jù)4號位,index+1,index = 5,五號位 i 又由6到20占據(jù)... ...
看圖
題目二:迷宮
基礎(chǔ)概念:
1,棧中的“先進(jìn)后出,后進(jìn)先出”什么意思
棧類似于彈匣,就像裝子彈壓彈進(jìn)彈匣一樣,一粒一粒壓進(jìn)去,但是退子彈是從最上面開始的,最先壓進(jìn)去的最后彈出來,最后一個壓進(jìn)去的第一個彈出來,這就是“先進(jìn)后出”,也叫“后進(jìn)先出”
2,棧的定義
?棧就是數(shù)據(jù)暫時存儲的地方,所以才有進(jìn)棧,出棧的說法
3,棧與隊列的區(qū)別
棧是把子彈子彈壓進(jìn)彈匣,后進(jìn)的先出;隊列就像排隊,你第一個排,那就第一個輪到你,這就是先進(jìn)先出,也叫后進(jìn)后出。dfs(深度優(yōu)先搜索)應(yīng)用棧,而bfs(廣度優(yōu)先搜索)應(yīng)用隊列。棧占用空間小,而堆中的bfs常用于最短路。
4,棧在計算機(jī)領(lǐng)域的解釋
棧作為一種數(shù)據(jù)結(jié)構(gòu),是只能在一端進(jìn)行插入和刪除的特殊線性表,它按照后進(jìn)先出的原則存儲數(shù)據(jù),先進(jìn)入的數(shù)據(jù)被壓入棧底,最后的數(shù)據(jù)在棧頂,需要讀數(shù)據(jù)的時候從棧頂開始讀。允許進(jìn)行插入和刪除操作的一段稱為棧頂(top),另一端稱為棧底(bottom)。棧底固定,而棧頂浮動;棧中元素個數(shù)為0時成為空棧。插入數(shù)據(jù)稱為進(jìn)棧(PUSH),刪除數(shù)據(jù)稱為退棧(POP),棧也稱后進(jìn)先出表。棧在函數(shù)調(diào)用時可以可以存儲斷點,做遞歸時要用到棧!
5,堆和棧的區(qū)別
棧快捷但自由度小,堆過程長但自由度大
6,內(nèi)存分配
一個由C/C++編譯的程序占用的內(nèi)存分為以下幾部分:
(1)棧區(qū)(stack)--由編譯器自動分配釋放,存放函數(shù)參數(shù)值,局部變量的值等。操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧
(2)堆區(qū)(heap)--由程序員分配釋放,若程序員不釋放,程序結(jié)束時可能由OS回收。它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式類似鏈表
(3)全局(靜態(tài))區(qū)(static)--初始化的全局變量和靜態(tài)變量在一塊區(qū)域,未初始化的在相鄰的另一塊區(qū)域。
(4)文字常量區(qū)--常量字符串放在這里
(5)程序代碼區(qū)--存放函數(shù)體的二進(jìn)制代碼
7,關(guān)于dfs,只要遞歸理解了,相關(guān)語法學(xué)習(xí)(這個我還沒學(xué))并練習(xí)過,也就差不多了
還涉及到:malloc函數(shù),stack(?;緮?shù)據(jù)結(jié)構(gòu)),pop()函數(shù),結(jié)構(gòu)體還有相關(guān)頭文件等,害,沒時間搞了,我先把C++基礎(chǔ)語法學(xué)完再回來
最后奉上幾張圖
?
?
?第二第三張圖片來源于以下博客
迷宮算法(DFS)_熱愛編程的大忽悠的博客-CSDN博客_迷宮算法
以下是我在學(xué)習(xí)dfs過程中看的博客,就差在了語法不懂,先去MOOC學(xué)習(xí)吧:
1,最短路徑問題(更新)_skycrygg的博客-CSDN博客_最短路徑問題
2,c++深度優(yōu)先搜索詳解_練習(xí)時長六年半的Programmer的博客-CSDN博客_c++深度優(yōu)先搜索
3,回溯法與深度優(yōu)先搜索(DFS)_lonely喆的博客-CSDN博客_回溯法和深度優(yōu)先算法區(qū)別
4,深度優(yōu)先搜索(DFS) 總結(jié)(算法+剪枝+優(yōu)化總結(jié))_HeartFireY的博客-CSDN博客
5,迷宮算法(DFS)_熱愛編程的大忽悠的博客-CSDN博客_迷宮算法
6,BFS和DFS_shiki11111的博客-CSDN博客_dfs和bfs
題目三:走方格?
題目
給定一個m*n方格陣,沿著方格邊線走,從左上角(0, 0)開始,每次只能往右或往下走一個單位距離,問走到右下角(m, n)一共有多少種不同走法
輸入
一行包含兩個整數(shù) m 和 n (m >= 1 && m <= 10) && (n >= 1 && n <= 10)
輸出
輸出一個整數(shù),表示走法數(shù)量
代碼
#include<iostream> using namespace std;int m, n, num = 0;int dfs(int x, int y) {if(x == m && y == n)num++;//走法數(shù)量+1else{if(x < m)dfs(x + 1, y);//遞歸行加一if(y < n)dfs(x, y + 1);//遞歸列加一} }int main() {while(cin>>m>>n){dfs(0, 0);cout<<num<<endl;num = 0;}return 0; }輸入輸出
1 1 2 1 2 3 2 2 6 2 3 10 3 3 20 10 10 184756分析?
1,首先我們明確,只能向右或下走,然后看圖
圖上粗線表示第一次路徑,代碼的關(guān)鍵在于第13行和第15行對dfs的遞歸,這也是深度優(yōu)先搜索的精髓
當(dāng)?shù)谝淮螡M足x == 2 && y == 3后,此時已到達(dá)(2, 3),函數(shù)會return回上一步,也就是(2, 2),但是下一步的路之前走過了,所以又返回到(2, 1),以此類推一直return到(1, 0),
開始第二條路徑: (1, 0) --> (1, 1) --> (1, 2) --> (1, 3) --> (2, 3)...然后繼續(xù)重復(fù)上述步驟
關(guān)于遞歸的理解其實沒什么好方法,首先你得知道你敲出dps(x + 1, y)類似代碼會出現(xiàn)什么樣的結(jié)果,多做點考察dfs的題,自然就懂了
總結(jié)
以上是生活随笔為你收集整理的蓝桥杯C++深度优先搜索(dfs)之组队,迷宫,走方格的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2100 年的世界会怎样?特拉华教授用机
- 下一篇: C++求阶乘