回溯法也可以叫做回溯搜尋法,是一種搜尋的方式,回溯和遞迴是相輔相成的,回溯是遞迴的副產品,只要有遞迴就會有回溯,所以可以簡單的理解回溯函式和遞迴函式是同一個函式。
大名鼎鼎的回溯法雖然很不好理解,但其本質就是暴力查詢,窮舉所有可能,然後找出我們想要的答案,並不是什麼高效的演算法,雖然有些可以剪枝一下,沒有更優化的方法了,至於為什麼不高效還要用,那沒別的更好的了能解決問題就不錯了還想咋滴。
回溯法可以解決組合、排列、切割、子集、棋盤(N皇后,解數獨)等問題,其中組合無序,排列有序。以上這幾類問題都不簡單。
回溯法解決的所有問題其實都可以抽象為樹形結構,因為它解決的都是在結合中查詢子集,集合的大小就構成了樹的寬度,遞迴的深度構成樹的深度(遞迴就要有終止條件,必然是一個棵高度有限的N叉樹)。
和遞迴函式一樣,三部曲:(1)確定回溯函式返回值和引數(一般不需要返回值,引數其實也不好確定,可以先寫邏輯,再定引數)(2)終止條件(3)回溯搜尋的遍歷過程邏輯。
回溯法的問題有一個套用的模板幫助解決問題:
void backtracking(引數) { if (終止條件) { 存放結果; return; } for (選擇:本層集合中元素(樹中節點孩子的數量就是集合的大小)) { 處理節點; backtracking(路徑,選擇列表); // 遞迴 回溯,撤銷處理結果 } }
終止條件說的就是一旦滿足了要求的條件(一般來說搜尋到葉子結點),就是找到了滿足條件的一條答案,把這個答案存放起來,並接受這層遞迴。for迴圈是樹的橫向遍歷,而遞迴呼叫時樹的深度遍歷,這樣就能把一棵樹都遍歷到了。