回溯法,又稱試探法,是常用的,基本的優選搜尋方法。常用於解決這一類問題:給定一定約束條件f(該約束條件常用於後面的剪枝)下求問題的乙個解或者所有解。
回溯法其實是暴力列舉的一種改進,因為其會聰明的filter掉不合適的分支,大大減少了無謂的列舉。若某問題的列舉都是可行解得話,也就是沒有剪枝發生,那麼回溯法和暴力列舉並無二異。
該回溯法先從解空間中選取任意乙個可能滿足約束條件f
的點x1
,然後從滿足f
的解空間中繼續選擇乙個點x2
,直到所找到的點構成乙個解s
或者找不到滿足約束條件f
的點時,開始回溯。回溯到上一層節點f,再另選滿足f
的解空間中的一點,繼續試探。
整個過程類似於乙個遞迴樹,因此回溯法常常採用dfs
的方法來實現。不考慮約束條件f
,整個遞迴樹的任一根節點root
到葉子節點leaf
的路徑path
都是無約束條件f
的原問題的乙個解。
回溯法解決的問題的一般特徵:能夠利用約束條件f
去快速判斷構成乙個完整解的一些區域性候選資訊partial candidates
是否可能最終構成乙個正確的、完整的解。
明確問題的解空間s
和約束條件f
.
利用深度優先搜尋,試探可能構成乙個完整解的候選節點,利用約束條件f
進行剪枝
2.1. 找到遞迴的base case
2.2. 利用約束條件f
判斷是否剪枝,一旦剪枝,則開始回溯(返回)
當遞迴到葉節點的時候,即得到原問題在約束條件f
下的乙個解,若要得到所有的可行解,則還需要考察根節點的其他分支。
回溯法注意事項:
1. 遞迴狀態的儲存和更新
2. 回溯點的處理(是否應該清除該回溯點之前對遞迴狀態產生的side effect
)
3. 解的蒐集
回溯法之經典問題:n皇后問題
public
class
nqueensdemo
public
void
solution(int n)
public
void
dfs(int i, int j, int solution, int occupiedrow, int occupiedcol, int occupiedtopbottom,
int occupiedbottomtop, list collector, int size)
// 8個方向
occupiedrow[i] = 1;
occupiedcol[j] = 1;
occupiedtopbottom[size - 1 + (i - j)] = 1;// 左上到右下的斜線 (i+d, j+d) 關係為i-j,
// 範圍為 -size + 1 ~ size - 1,
// 所以左右各加size - 1歸到區間
// 0~2size - 2, 關係為 size - 1
// + (i - j), 分配的陣列大小為 2size
// - 1
occupiedbottomtop[i + j] = 1;// 左下到右上的斜線(i-d, j+d)和(i+d, j-d) 關係為 i+j
// 分配的陣列大小為 2size - 1
// 尋找下乙個皇后放置的位置
i = i + 1;
for (int n = 0; n < size; n++)
// 回溯後, clear flag,恢復原狀
i = i - 1;
occupiedrow[i] = 0;
occupiedcol[j] = 0;
occupiedtopbottom[size - 1 + (i - j)] = 0;
occupiedbottomtop[i + j] = 0;
}public
void
print(list collector, int n) }}
}}
public
class
solution
boolean found = false;
for (m = 0; m < 9; m++)
if (found)
break;
}for (int num = 0; num < 9; num++)
if (rowcount[m][num] == 0 && colcount[n][num] == 0 && subboxcount[m / 3 * 3 + n / 3][num] == 0)
if (dfs(m, n, (char) (num + base), board, rowcount, colcount, subboxcount, fillednum))
break;
}public
boolean
dfs(int i, int j, char c, char board, int rowcount, int colcount, int subboxcount,
int fillednum)
}if (found)
break;
else
n = 0;
}for (int num = 0; num < 9; num++)
}// failed 該格仔無論填啥都無解,所以clear所做的更改
board[i][j] = '.';
rowcount[i][number] -= 1;
colcount[j][number] -= 1;
subboxcount[i / 3 * 3 + j / 3][number] -= 1;
fillednum -= 1;
return
false;
}}
常用演算法之回溯法
回溯演算法實際上乙個類似列舉的搜尋嘗試過程,主要是在搜尋嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就 回溯 返回,嘗試別的路徑。回溯法是一種選優搜尋法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,...
演算法之回溯法
回溯法非常適合由多個步驟組成的問題,並且每個步驟都有多個選項。當我們在某一步選擇了其中乙個選項時,就進入下一步,然後面臨新選項,重複選擇,直至最終狀態。經典面試題1 矩陣中的路徑 詳見 劍指offer 面試題12 易錯點 1.由於路徑不能重複進入矩陣的格仔,因此還需定義和字元矩陣大小一樣的布林值矩陣...
演算法之回溯法
求解步驟 1,定義給定問題的解向量解空間 子集樹 排列樹 2,設計剪支函式 限界函式及約束函式 3,深度優先遍歷結合剪支得出解 求解過程 1,是否為完全解,是則輸出 2,是否為部分解,是則進行下乙個解分量的判斷 3,是否為當前可選集合中的最後乙個元素,是則回溯,重新判斷上乙個節點,否則判斷可選集合中...