什么是回溯算法
回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發(fā)現(xiàn)已不滿足求解條件時巾陕,就 “回溯” 返回,嘗試別的路徑纪他。
回溯法是一種選優(yōu)搜索法鄙煤,按選優(yōu)條件向前搜索,以達到目標茶袒。但當探索到某一步時梯刚,發(fā)現(xiàn)原先選擇并不優(yōu)或達不到目標,就退回一步重新選擇薪寓,這種走不通就退回再走的技術為回溯法亡资,而滿足回溯條件的某個狀態(tài)的點稱為 “回溯點”。許多復雜的向叉,規(guī)模較大的問題都可以使用回溯法锥腻,有“通用解題方法”的美稱。
回溯算法的基本思想是:從一條路往前走植康,能進則進旷太,不能進則退回來,換一條路再試。
八皇后問題
我們學習了什么是回溯算法供璧,聽起來很簡單存崖,但具體怎么使用呢?下面我們通過一個例子來說明回溯算法的用法睡毒。
八皇后問題:有一個8X8的棋盤来惧,希望往里放8個棋子(皇后),每個棋子所在的行演顾、列供搀、對角線都不能有另一個棋子,找到所有滿足這種要求的放棋方式钠至。
解題思路:把這個問題劃分成8個階段葛虐,依次將8個棋子放到第一行、第二行棉钧、第三行....第八行屿脐。在放置的過程中,不停地檢查當前的方法宪卿,是否滿足要求的诵。如果滿足,則跳到下一行繼續(xù)放置棋子佑钾;如果不滿足西疤,那就換一種方法,繼續(xù)嘗試休溶。
代碼實現(xiàn)如下:
public class Solution {
int[] result = new int[8]; // 全局或成員變量代赁,下標表示行,值表示queen存儲在哪一列
public void Cal8Queens (int row) { // 調用方式:Cal8Queens(0);
if (row == 8) { // 8個棋子都放置好了兽掰,打印結果
PrintQueens (result);
return; // 8行棋子都放好了管跺,已經(jīng)沒法再往下遞歸了,所以就return
}
for (int column = 0; column < 8; ++column) { // 每一行都有8中放法
if (IsOK (row, column)) { // 有些放法不滿足要求
result[row] = column; // 第row行的棋子放到了Column列
Cal8Queens (row + 1); // 考察下一行
}
}
}
private bool IsOK (int row, int column) { // 判斷row行column列放置是否合適
int leftup = column - 1, rightup = column + 1;
for (int i = row - 1; i >= 0; --i) { // 逐行往上考察每一行
if (result[i] == column) return false; // 第i行的column列有棋子嗎禾进?
if (leftup >= 0) { // 考察左上對角線:第i行l(wèi)eftup列有棋子嗎?
if (result[i] == leftup) return false;
}
if (rightup < 8) { // 考察右上對角線:第i行rightup列有棋子嗎廉涕?
if (result[i] == rightup) return false;
}
--leftup;
++rightup;
}
return true;
}
private void PrintQueens (int[] result) { // 打印出一個二維矩陣
for (int row = 0; row < 8; ++row) {
for (int column = 0; column < 8; ++column) {
if (result[row] == column) Console.Write ("Q ");
else Console.Write ("* ");
}
Console.WriteLine ();
}
Console.WriteLine();
}
}
總結
回溯算法的思想非常簡單泻云,大部分情況下狐蜕,都是用來解決廣義的搜索問題:從一組可能的解中宠纯,選擇出一個滿足要求的解层释。
回溯算法非常適合用遞歸來實現(xiàn),在實現(xiàn)的過程中,剪枝操作是提高回溯效率的一種技巧廉白。利用剪枝,并不需要窮舉搜索所有的情況猴蹂,從而提高搜索效率院溺。