回溯算法學習

外在

顯然,給你一個選擇列表,讓你在選擇列表中不斷的進行選擇。最終返回一個包含所有選擇的結果集

結果集 fun(選擇列表 nums) {

}

構造基本解題結構

結果集都是從從路徑一步步走出來的,backtrack多出了一個路徑參數,無需返回。

結果集 result;
void backtrack(選擇列表 chooses, 路徑 track){

}
結果集 fun(選擇列表 chooses) {
    // 路徑是結果的子集,一步步擴充成結果
    路徑 track;
    backtrack(chooses, track);
    return res;
}

構造回溯結構

回溯是一個遞歸結構,帶結束條件,調用自身。
每次選擇是可多選的,故以遍歷選擇列表的方式逐個嘗試。
由於嘗試時,將選擇添加進了路徑中,故下次選擇前,要回退上次的選擇。
選擇不合法時咋辦?兩種做法:在開頭排除,在遍歷嘗試時不管;認爲調用傳進來的必然合法,調用前先完成排除。

void backtrack(選擇列表 chooses, 路徑 track) {
   
    if (觸發結束條件) {
        result.add(track);
        // 如果沒有return,則可能沿着剩餘選擇再搞搞,說不定會死循環
        return;
    }
	// 遍歷選擇列表
    for (choose:chooses) {
        if (選擇不合法)
            continue;
        // 做選擇,路徑中加入當前選擇
        track.add(choose);
        // 進入下一層決策樹
        backtrack(nums, track);
        // 回退選擇,還原原本的track再進入下個操作
        track.remove(choose);
    }
}

選擇和回退是一對的,是爲了不影響數據。此外,把路徑copy一個新的也闊以啊,就是效率低。

回溯算法只返回其中一個結果

boolean backtrack(選擇列表 chooses, 路徑 track) {
   
    if (觸發結束條件) {
        result.add(track);
        // 如果沒有return,則可能沿着剩餘選擇再搞搞,說不定會死循環
        return true;
    }
	// 遍歷選擇列表
    for (choose:chooses) {
        if (選擇不合法)
            continue;
        // 做選擇,路徑中加入當前選擇
        track.add(choose);
        // 進入下一層決策樹
        if(backtrack(nums, track)){
        	return true;
        }
        // 回退選擇,還原原本的track再進入下個操作
        track.remove(choose);
    }
    return false;
}

再次簡化的話,可以去掉result這個量

與動態規劃的關係

能採用動態規劃的解決的問題,也是符合回溯算法特徵的,動態規劃的優勢在於重疊子集上,做了更大幅度的剪枝。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章