常用演算法之 回溯法

2022-09-02 03:45:11 字數 3102 閱讀 5149

回溯法,又稱試探法,是常用的,基本的優選搜尋方法。常用於解決這一類問題:給定一定約束條件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,是否為當前可選集合中的最後乙個元素,是則回溯,重新判斷上乙個節點,否則判斷可選集合中...