1. 程式人生 > 實用技巧 >回溯法的總結

回溯法的總結

回溯法的總結


​ 回溯法的解空間樹主要包含\(n\)叉樹、排列樹、子集樹。

​ 例如在回溯法求解\(N\)皇后問題時,採用\(n\)叉樹的結構,如下圖所示:

​ 該解空間即為\(n\)叉樹的情況,當\(x_1\)選擇\(1\)時,即進入第一個分支,進而在通過剪枝函式判斷,當前分支是否有可能為最優解,若為可能產生最優解則展開第一個分支;若不可能,則剪去該分支。依次遞迴下去對\(x_2, x_3, ...\)分別求解,當到達最後樹的葉子結點,即表示這種情況可行,就可以進行後續操作,包括儲存路徑或儲存最優解等。
​ 當一條分支執行完畢後,退出當前遞迴,即返回上一層的狀況,這就需要我們將進入分支時,對資料的修改撤回,體現在BackTrack1(t + 1);

程式碼前後的對稱性。這樣就能確保從第一條分支遞迴結束,返回根節點再執行第二條分支時,資料恢復到根節點最初的資料。
​ 最大團問題求解時,該特點明顯,如下:

void BackTrack(int i) {
    if (i > n) {
        for (int j = 1; j <= n; j++)
            bestx[j] = x[j];
        bestn = cn;
        return ;
    }
    int ok = 1;
    for (int j = 1; j < i; j++)
        if (x[j] == 1 && a[i][j] == 0) {
            ok = 0;
            break;
        }
    if (ok) {
        x[i] = 1;
        cn++;
        BackTrack(i + 1);
        cn--;
    }
    if (cn + n - i > bestn) {
        x[i] = 0;
        BackTrack(i + 1);
    }
}

​ 可以發現在\(17\)行中BackTrack(i + 1);的前後程式碼是對稱的,cn++在退出遞迴時,進行了cn--撤銷了對cn的操作。而x[i] = 1;由於每次遞迴時都需要重新賦值,因此無需寫出其對稱程式碼。
9~13行即為剪枝函式,將結點與已成團的結點不相連的分支直接剪去,不進行遞迴訪問,提高搜尋效率。20~23為限界函式,要求右子樹中,剩下的所有結點數和以及抱團的結點數大於當前最優解數,這樣才有可能有更好的解,進行遞迴訪問,

總得來說,回溯法主要是遍歷問題的所有可行解,將所有的解構成樹的解空間,在通過剪枝函式和限界函式,剪去錯誤的分支,降低無效的搜尋,以此提高搜尋效率。