回溯算法学习

外在

显然,给你一个选择列表,让你在选择列表中不断的进行选择。最终返回一个包含所有选择的结果集

结果集 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这个量

与动态规划的关系

能采用动态规划的解决的问题,也是符合回溯算法特征的,动态规划的优势在于重叠子集上,做了更大幅度的剪枝。

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