Skip to content

Backtracking 第二讲

还记得上一节所讲的回溯法投色子吗?

浪费了很多算力,产生了很多不必要的结果

那我们应该怎样改进呢?

优化

剪枝

**原理:**如果在某一时刻我们确信从此开始将无法继续,或许我会立刻撤回并且停止.

所以我们只需要在之前的选择中做出一些限制,使得之后的选择更加有利.

else if (desiredSum >= dice * 1 && desiredSum <= dice * 6) {.....}

这就被称之为"剪枝""!


回溯法的整体策略就是:

  • 若面临选择,则处理其中一个选择,若处理后仍有选择,则回到之前的选择点继续处理,直到所有选择都处理完毕.
  • 你进行选择,然后谈起其后每一种可能的发展,随后再撤销选择.
  • 选择,探索,撤销选择每一种可能性

例子

问题: Permute Vector(排列向量)

  • 编写一个名为 permute 的函数,该函数接受一个字符串的向量作为参数,并输出该向量中所有可能的字符串重排列。输出的排列顺序可以是任意的。

**示例:**如果 v 包含 { "a", "b", "c", "d" },你的函数应输出这些排列:

alt text

思路:

  • 我们可以先将字符串向量中的每个字符串看作是一个字符,然后将其排列组合成新的字符串.
  • 我们可以用一个循环来遍历向量中的每个字符串,然后将其与其他字符串组合成新的字符串,并将其加入到结果集中.
  • 我们可以用一个递归函数来实现这个过程.
c++
void permuteHelper(Vector<string>& v, Vector<string>& chosen){
    if (v.isEmpty()){
        cout << chosen << endl;
    }else{
        for (int i = 0; i < v.size(); i++)
        {
            string s = v[i];
            chosen.add(v[i]);
            v.remove(i);

            permuteHelper(v,chosen);

            chosen.remove(chosen.size()-1);
            v.insert(i,s);

        }
    }
}

void permute(Vector<string>& v)
{
    Vector<string> chosen;
    permuteHelper(v, chosen);

}

这其实也是一种树状结构,我们可以用递归来实现.

回退出去以后进入 for 的下一个遍历,我们将当前的字符串加入到 chosen 中,然后将其从 v 中移除,然后递归调用 permuteHelper,直到 v 为空,此时输出 chosen.

然后我们将当前的字符串从 chosen 中移除,然后将其重新插入到 v 的相应位置,继续下一个遍历.

这样我们就实现了排列组合的过程.