java dfs_Java数据结构与算法 深搜(DFS)的简单使用(一)之排列组合
今天,我們來簡(jiǎn)單介紹一下深度優(yōu)先搜索(DFS)的概念和使用。
在百度詞條中,對(duì)深搜的解釋是這樣的。
百度詞條中的解釋
由此,我們可知,深搜是廣泛運(yùn)用到 圖 中的搜索方法之一。
用深度優(yōu)先搜索遍歷圖的基本思路是:
(1)訪問頂點(diǎn)v;
(2)依次從v的未被訪問的鄰接點(diǎn)出發(fā),對(duì)圖進(jìn)行深度優(yōu)先遍歷;直至圖中和v有路徑相通的頂點(diǎn)都被訪問;
(3)若此時(shí)圖中尚有頂點(diǎn)未被訪問,則從一個(gè)未被訪問的頂點(diǎn)出發(fā),重新進(jìn)行深度優(yōu)先遍歷,直到圖中所有頂點(diǎn)均被訪問過為止?!‘?dāng)然,當(dāng)人們剛剛掌握深度優(yōu)先搜索的時(shí)候常常用它來走迷宮.事實(shí)上我們還有別的方法,那就是廣度優(yōu)先搜索(BFS,我們以后在做介紹).
但在今天,為了簡(jiǎn)化問題,我們不以 圖 作為問題來論述 深搜 ,我們用排列組合的思想來運(yùn)用 深搜。好,我們先來看一道問題。
題目
顯而易見,這道題可以使用循環(huán)來枚舉每一個(gè)數(shù)字,但是這樣需要用帶9層循環(huán),并且滿足這樣的數(shù)字還不只一個(gè)。如果使用這樣的計(jì)算方式,會(huì)增加大量的時(shí)間復(fù)雜度(這里的時(shí)間復(fù)雜度(O)= n^9),給CPU很大的負(fù)擔(dān),甚至有些計(jì)算機(jī)系統(tǒng)不允許執(zhí)行。
這道題也能在第一個(gè)數(shù)上從123遍歷到333,然后計(jì)算出后面的第二個(gè)數(shù),第三個(gè)數(shù),然后再?gòu)闹姓页霾恢貜?fù)的3個(gè)3位數(shù),這是一個(gè)很好的方法,但是,這跟人用計(jì)算器來計(jì)算結(jié)果有什么區(qū)別?我們是要使用計(jì)算機(jī)從根本來解決這個(gè)問題。(這兩種方法會(huì)在后面提供C\C++和JAVA的代碼)
在這里,我們重點(diǎn)講述更為合理的深度優(yōu)先搜索方法。這里需要用到 排列組合 的思想,我們先來解釋3個(gè)數(shù)的排列組合,再來類比題目中的9個(gè)數(shù)的排列組合。
3個(gè)數(shù)的排列組合
這里我們假設(shè)有3個(gè)盒子,分別標(biāo)記上1號(hào),2號(hào),3號(hào)。我們現(xiàn)在需要把1、2和3,這三個(gè)數(shù)字放在其中,有多少種放法呢?這個(gè)很簡(jiǎn)單,即便是沒有學(xué)過排列組合都能計(jì)算出多少種放法。我們先來枚舉出組成的3位數(shù)吧,有123、132、213、231、321、312,共6種放法。然而,我們只需要運(yùn)算 3*2*1 ,就能得到有6種放法,但是計(jì)算機(jī)應(yīng)該怎么去計(jì)算呢?
這里,我們請(qǐng)一個(gè)叫小曦的同學(xué)幫忙,讓他模擬計(jì)算機(jī)運(yùn)行,我們給他規(guī)定好方法。
首先,小曦手中有3張標(biāo)著有1、2、和3的卡片,面前有如上圖所示的盒子。我們讓小曦先去1號(hào)盒放一張卡片,再讓小曦走到下一個(gè)盒子,也就是2號(hào)盒放一張卡片,最后到3號(hào)盒子放最后一張,即便是后面還有盒子,但小曦手中沒有卡片了,也是無法去放的。
現(xiàn)在,我們讓小曦開始去放卡片,小曦來到1號(hào)盒子前,果斷的放了標(biāo)有1的卡片,然后來到2號(hào)盒子前,放了標(biāo)有2的卡片,最后,小曦只能在第3號(hào)盒子放進(jìn)標(biāo)有3的卡片。這樣,就形成了一個(gè)3位數(shù)的數(shù)字——123。我們記錄下這個(gè)數(shù)字,讓小曦收回放在盒子的卡片,這個(gè)時(shí)候,小曦正好在3號(hào)盒子前,所以小曦拿起了3號(hào)盒子中的標(biāo)有3的卡片,然后退回到緊挨著3號(hào)盒子的2號(hào)盒子,拿起了2號(hào)盒子中標(biāo)記著數(shù)字2的卡片,這時(shí)候,小曦的手中拿著有標(biāo)記著2、3數(shù)字的兩張卡片,小曦發(fā)現(xiàn),手中的數(shù)字3卡片還沒有放在過盒子2號(hào)中,于是小曦將手中的數(shù)字3卡片放在2號(hào)盒子中,然后來到3號(hào)盒子前,只能把數(shù)字2的卡片放在3號(hào)盒子中。這時(shí),就形成了第二個(gè)3位數(shù)——132。我們?cè)賹?32記錄好。讓小曦收回卡片,小曦按照原來的方法,走回2號(hào)盒子前收回?cái)?shù)字3卡片后,發(fā)現(xiàn)2、3都已經(jīng)放在盒子里面過了,于是小曦只好退回到1號(hào)盒子前收回?cái)?shù)字1的卡片,然后發(fā)現(xiàn)1號(hào)盒子里面還未放過數(shù)字2、3的卡片,于是放進(jìn)了數(shù)字2的卡片。(類似于棧一樣,后進(jìn)先出)
就這樣,小曦一直重復(fù)著這一過程,最終得到123、132、213、231、321、312,6種的放法。我們把圖放上來,方便大家理解。
開始
第一步
第二步
第三步,記錄數(shù)字123
第四步
第五步
第六步
第七步,記錄數(shù)字132
后面圖略。。。
現(xiàn)在,我們按照題中的要求,把3個(gè)數(shù)擴(kuò)展到9個(gè)數(shù)。
9個(gè)數(shù)的排列組合
還是按照小曦放3個(gè)數(shù)字的方法來放9個(gè)數(shù)字。然后讓1、2、3號(hào)盒子構(gòu)成的數(shù)字與4、5、6號(hào)和7、8、9號(hào)盒子構(gòu)成的數(shù)字形成如題所示的方式,這樣,1到9的數(shù)字不會(huì)重復(fù)出現(xiàn)。好,我們先把代碼搬上來。
實(shí)例代碼
運(yùn)行結(jié)果
這里,我使用了私有的全局的內(nèi)部類來保存深度優(yōu)先搜索算法,供主函數(shù)調(diào)用,并用static保存全局變量。顯然,深搜的核心就是方法(函數(shù))的遞歸。我們下面來介紹步驟。
初始化與book
這里解釋一下,這里構(gòu)造器構(gòu)造出指定了長(zhǎng)度的數(shù)組在沒有賦值以前默認(rèn)為0。C\C++中,全局變量在沒有賦值以前也是默認(rèn)為0。所以這里不需要再初始化為0。我們?cè)谶@里構(gòu)造了卡片和盒子,a的下標(biāo)表示幾號(hào)盒子,book的下標(biāo)表示卡片上的數(shù)字(類似于桶排序的方法)。
放卡片
這里用了book來標(biāo)記卡片是否已經(jīng)放在盒子中,而在book中間的toBeUsed回調(diào),則是往下一個(gè)盒子移動(dòng)。
判斷是否放完盒子和判斷是否滿足條件
調(diào)用方法且開始時(shí)站在第一個(gè)盒子前
到這里基本就已經(jīng)解決問題,如果還是無法深搜的概念,可以反復(fù)理解這段代碼。下面,我們提供C\C++的代碼。
C\C++示例代碼
我們來看第二種方法的C\C++代碼,JAVA代碼這里省略。(基本一樣)
這里使用了指針來讀取每一個(gè)得到數(shù),并保存在array數(shù)組中,每保存一個(gè)數(shù)的時(shí)候,就判斷是否存在重復(fù)的。
C\C++示例代碼
九重循環(huán)的枚舉方法就在這里省略。
注:mooc上的編譯器可能存在問題,不支持復(fù)雜的運(yùn)算。也可能是超時(shí)問題(幾率很小)。
總結(jié)
以上是生活随笔為你收集整理的java dfs_Java数据结构与算法 深搜(DFS)的简单使用(一)之排列组合的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RSTray.exe是什么进程?RSTr
- 下一篇: java reader_Java之字符输