leetcode 回溯法 模板

/**
* dfs 模板.
* @param[in] input 输入数据指针
* @param[out] path 当前路径,也是中间结果
* @param[out] result 存放最终结果
* @param[inout] cur or gap 标记当前位置或距离目标的距离
* @return 路径长度,如果是求路径本身,则不需要返回长度
*/
void dfs(type &input, type &path, type &result, int cur or gap) {
if (数据非法) return 0; // 终止条件
if (cur == input.size()) { // 收敛条件
// if (gap == 0) {
将path 放入result
}
if (可以剪枝) return;
for(...) { // 执行所有可能的扩展动作
执行动作,修改path
dfs(input, step + 1 or gap--, result);
恢复path

}


一段来自百度百科对回溯法思想的描述:

在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。

   可以把回溯法看成是递归调用的一种特殊形式。其实对于一个并非编程新手的人来说,从来没使用过回溯法来解决问题的情况是很少见的,不过往往是“对症下药”,针对特定的问题进行解答。这些天看了《算法设计手册》回溯法相关内容,觉得对回溯法抽象的很好。如果说算法是解决问题步骤的抽象,那么这个回溯法的框架就是对大量回溯法算法的抽象。本文将对这个回溯法框架进行分析,并且用它解决一系列的回溯法问题。文中的回溯法采用递归形式。

  在进一步的抽象之前,先来回顾一下DFS算法。对于一个无向图如下图左,它的从点1开始的DFS过程可能是下图右的情况,其中实线表示搜索时的路径,虚线表示返回时的路径:

 

  可以看出,在回溯法执行时,应当:保存当前步骤,如果是一个解就输出;维护状态,使搜索路径(含子路径)尽量不重复。必要时,应该对不可能为解的部分进行剪枝(pruning)。

  下面介绍回溯法的一般实现框架:

复制代码
bool finished = FALSE; /* 是否获得全部解? */
backtrack(int a[], int k, data input)
{
    int c[MAXCANDIDATES]; /*这次搜索的候选 */
    int ncandidates; /* 候选数目 */
    int i; /* counter */
    if (is_a_solution(a,k,input))
    process_solution(a,k,input);
    else {
        k = k+1;
        construct_candidates(a,k,input,c,&ncandidates);
        for (i=0; i<ncandidates; i++) {
            a[k] = c[i];
            make_move(a,k,input);
            backtrack(a,k,input);
            unmake_move(a,k,input);
            if (finished) return; /* 如果符合终止条件就提前退出 */
        }
    }
}

对于其中的函数和变量,解释如下:

  a[]表示当前获得的部分解;

  k表示搜索深度;

  input表示用于传递的更多的参数;

  is_a_solution(a,k,input)判断当前的部分解向量a[1...k]是否是一个符合条件的解

  construct_candidates(a,k,input,c,ncandidates)根据目前状态,构造这一步可能的选择,存入c[]数组,其长度存入ncandidates

  process_solution(a,k,input)对于符合条件的解进行处理,通常是输出、计数等

  make_move(a,k,input)unmake_move(a,k,input)前者将采取的选择更新到原始数据结构上,后者把这一行为撤销。

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值