本文 → 《【算法】藍橋杯dfs深度優先搜索之湊算式總結》java
相關文章 →《【算法】藍橋杯dfs深度優先搜索之排列組合總結》算法
→《【算法】藍橋杯dfs深度優先搜索之圖連通總結》數組
曾幾什麼時候這個詞如今用正適合不過了。數據結構
曾幾什麼時候我仍是對dfs算法一臉懵x的狀態,雖然說大二的時候學過數據結構,可是那一學期被我荒廢了......詳情等我畢業了再說吧。app
還有四天就要考藍橋杯了,我分析了近四年的藍橋杯(B組)題型,分類純屬我的理解,並不是官方宣佈,以下表:函數
注:測試
如下DFS表明Depth First Search首字母縮寫,即深度優先搜索,簡稱深搜spa
如下DP表明Dynamic Programming首字母縮寫,即動態規劃,沒有簡稱 : ).net
分類 | 題號 | 總分 |
---|---|---|
水題 | 1(3分)、2(5分)、4(11分) | 19分 |
DFS/爆破 | 3(9分)、5(15分)、7(21分) | 45分 |
冒泡設計 (加法乘法) |
6(17分) | 17分 |
取餘 (飲料換購) |
8(13分) | 13分 |
矩陣 | 9(25分) | 25分 |
DP | 10(31分) | 31分 |
分類 | 題號 | 總分 |
---|---|---|
遞推 | 1(3分)、2(5分) | 8分 |
函數調用 | 4(11分) | 11分 |
DFS/爆破 | 3(9分)、5(13分)、 6(15分)、7(19分)、 8(21分) |
77分 |
DP | 9(23分) | 23分 |
數據結構 | 10(31分) | 31分 |
分類 | 題號 | 總分 |
---|---|---|
文件處理 | 1(5分)、3(13分) | 18分 |
DFS/爆破 | 2(11分)、4(17分) | 28分 |
水題 | 5(7分) | 7分 |
DP | 6(9分)、8(21分) | 30分 |
日期問題 | 7(19分) | 19分 |
二分問題 | 9(23分) | 23分 |
前綴和 | 10(25分) | 25分 |
分類 | 題號 | 總分 |
---|---|---|
水題 | 1(5分)、2(7分) | 12分 |
複數 | 3(13分) | 13分 |
排序 | 5(9分)、6(11分) | 20分 |
找規律 | 7(19分) | 19分 |
尺取法 | 8(21分) | 21分 |
DFS/爆破 | 9(23分) | 23分 |
DP | 4(17分)、10(25分) | 42分 |
能夠看到每一年藍橋杯都會考察dfs類型的題,並且分值在23-77分之間不等,雖然說分值成逐年降低的趨勢,但怎麼說也有20+分,藍橋杯滿分150分,普通人(我就是普通人中之一)總共能拿到的分數大概在80分左右,而DFS就包括在這80分以內,因此必定要掌握好。
以上是對題型及分值的分析,接下來分析一下爲什麼藍橋杯總要考dfs算法?首先看一則人物百科:
再來看一下「深度優先搜索」的百度詞條:
還有一點值得提出,這位大神是中國政府外聘千人計劃之一,目前好像在中國清北或港大其中一個學校任教。
藍橋杯做爲一個算法類競賽,再退一步講,怎麼說也得給老前輩一個面子吧。
綜上所述,藍橋杯考dfs算法的機率賽過千足金含金量的比率!
下文的大部分靈感均來自於【CSDN】梅森上校《JAVA版本:DFS算法題解兩個例子(走迷宮和求排列組合數)》
下面會貼出藍橋杯第六屆B組省賽第3題,第5題;第七屆B組省賽第3題,第8題;第八屆B組省賽第2題,共5道題。
由於它們都是:湊算式
【分析】
總共有8個不一樣的字,每一個字都表明不一樣的數,申請一個一維數組a[8]存儲這8個不一樣的數。
a[8]對應有下標index:0至7
因此dfs方法定義爲
而後設計結束條件,就是index等於8,越界了,表明找夠了8個數,嘗試進行判斷是否構成等式。
若是index沒有越界,a[]數組沒存夠8個數,就進行搜索。
由於從0至9搜索,且每一個數不能重複,因此每訪問一個都須要標記一下,visited[i] 爲 0 表明未訪問,爲 1 表明已訪問。
經過數學分析,祥字不可能爲0,不然沒法進位,三字必爲1,由於十進制進位只能進1,因此最終搜索代碼以下:
【完整代碼】
沒看懂這道題?不要緊。繼續往下看。
【分析】
這是一道填空題,基本代碼已經給出來了,我只是借題發揮,講解一下dfs算法。
上一題是8個數,咱們設置了一個a[8],這道題是9個數,因此設置一個a[9]
一樣須要一個index:0至8
這道題和上一道題的區別在於題目用了dfs()方法多了一個數組參數,以下
結束條件和上一題相似,當index爲9時,越界。
若是index不爲9,表明還沒湊夠9個數,深搜。上一題深搜以前是作標記,深搜以後重置標記,這一題相似,深搜以前交換,深搜以後重置交換,代碼以下:
這道填空題須要注意的是,不要徹底照抄以至於連 int 都抄上了,致使 t 被聲明兩次,報錯。
【完整代碼】
又沒看懂?不要緊。繼續往下看。
此題和第二道題相似,都是1-9九個數字,不過這裏要注意的是,第二題用乘法代替了除法,這道題雖說也能夠改爲乘法,可是會相對麻煩一點,乾脆就直接用除法,一旦涉及到除法,就有可能產生浮點數,因此咱們在聲明數組的時候不能再聲明爲int了,必須聲明爲double。
index仍是int的,取值範圍爲0至8
dfs方法定義以下:
結束條件就是index==9,越界
當index不夠9的時候,進行深搜
【完整代碼】
固然,這道題也能夠像第一題「三羊獻瑞」那樣,使用遞歸以前標記法
【標記法完整代碼】
對visited初始化的說明:
Java語言int型數組初始化時會自動賦值爲0,可是我爲了直觀表達,因此選擇了顯式初始化。
今天已經深夜1:22,還有一個四平方和沒有寫,明天再寫
我必定會回來的......
我又回來了,繼續看題。
經過上面的三道題,我想如今的dfs的套路應該已經有一些印象了吧。
由於是四平方,要存四個數,因此咱們思考都不用思考,先整個a[4]
同理,須要一個index,0至3
由於前幾道題的程序都不須要咱們進行輸入,這道題須要輸入一個num,並且還須要進行等式判斷,因此須要做爲dfs()方法的一個參數,這樣dfs()方法定義以下:
遞歸結束條件爲index==4,越界,表明a[]數組存夠4個數了,能夠進行等式判斷了,代碼以下:
若是index不等於4,表明4個數還沒找夠,深搜。這裏要注意3件事:
一是深搜的範圍,最大範圍是三個0和輸入數字的開根號。
二是Java中Math.sqrt()方法返回值是double,最好轉爲int,讓兩個int進行比較。
三是遞歸以前要不要留下已訪問的標記,或者交換?從給出的輸入樣例能夠看出來,有0 0 1 2 、 0 2 2 2 這樣的輸出,因此說數字是能夠重複使用的,那麼就不必進行標記或者交換了。這也是這道題和前三道題區別之一。
綜上,搜索代碼以下
【完整代碼】
【等等,這道題還沒完】
畢竟是一道23分的大題,尊重一下出題人嘛,怎麼會讓你這麼輕鬆的拿分呢?
若是按照上面的代碼,輸入5,會輸出下面的結果
顯然,人家只要第一行。在趙壯同窗的指點下,直接在輸出下面加一句System.exit(0);就能夠了。
【再等最後一下,真的】
雖說上面的代碼可以實現輸出第一行,可是深搜畢竟是一種盲目的遞歸,進行大量無用的嘗試,最終致使超時。我僅僅是拿這道題讓你們更深刻了的理解一下dfs這個算法。就上面的代碼,我測試了一下 773535 這個輸入,Eason的《很久不見》循環播放三遍了都還沒跑出來,這要是提交了藍橋比賽,那就GG了......
其實深搜大部分均可以用for循環暴力破解代替,這樣能夠減小一下盲目性,好比這道題的解法能夠參考下面這篇文章:
【CSDN】有夢就不怕痛《藍橋杯 四平方和》
Java版代碼以下(運行飛通常的流暢):
好了,我已經逐個分析了四道題了,原本已經快要分析吐了,不想再分析了。可是後來想了想小王子裏面那句話:「每一個大人都曾經是個孩子,可又有幾我的記得呢?」還有我國晉惠帝說的一句千古名言:「何不食肉糜?」
下面這道題就算是對「湊算式」這類題型的一個總結吧。
有了上面四道題的經驗,看到這種湊算式的題,上來想都不用想:
第一件事,就是設數組
第二件事,數字可否重複使用?能,略過這條;不能,設標記數組,或者交換(我我的偏向設標記數組)
第三件事,定義dfs()方法
第四件事,判斷遞歸結束條件,一般是index越界,並進行等式判斷
第五件事,還未湊齊數,深度優先搜索
第六件事,寫main()方法
完事
【完整代碼】
這道題有個坑就是要去重,由於題中說明「旋轉,鏡像後相同的算一種」,因此最後要count/6.這個純靠經驗了,有過旋轉經驗的就知道,每一個數都有機會佔在頂點上,全部數固定後,轉動的話,等於每一個數計算了3次,因此要除以3;對於鏡像,一樣是靠經驗,若是你知道從鏡子裏看左右會對換的話,就會知道要除以2,總共除以6.
在沒作這道題以前,我是不知道鏡像是什麼樣的,所以我還特地拿個鏡子照了照。
這篇文章就到此結束吧,我要開一個新坑了,明天應該能發佈新文章:
若是看完這5道題還不會這種「湊算式」的題,請發QQ郵箱:424171723@qq.com 或 直接加我QQ,進行手把手教學。
【參考文章】