目录
简介:
回溯法主要用在递归的树型问题中,该算法实际上是一个类似枚举的搜索尝试过程,在搜索过程中寻找问题的解,当发现当前问题状态无解时,就“回溯”返回,尝试别的路径。
判断是否可以用回溯法很简单,拿到一个问题,你感觉如果不穷举一下就没法知道答案,那就可以开始回溯了。
一般回溯的问题有三种:
- Find a path to success 有没有解
- Find all paths to success 求所有解
a) 求所有解的个数
b) 求所有解的具体信息
3. Find the best path to success 求最优解
理解回溯:给一堆选择, 必须从里面选一个. 选完之后我又有了新的一组选择.
回溯可以抽象为一棵树,我们的目标可以是找这个树有没有good leaf,也可以是问有多少个good leaf,也可以是找这些good leaf都在哪,也可以问哪个good leaf最好,分别对应上面所说回溯的问题分类。
good leaf都在leaf上。good leaf是我们的goal state,leaf node是final state,是解空间的边界。
回溯的通用模板:
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意添加
return;
}
for(当前状态的每一个可能性){
if(该可能性合法(比如没被标记过等等)){ // 剪枝
修改操作;//根据题意来添加
标记;
dfs(设置下一位);
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
关于回溯的三种问题,模板略有不同,
第一种,返回值是true/false。
第二种,求个数,设全局counter,返回值是void;求所有解信息,设result,返回值void。
第三种,设个全局变量best,返回值是void。
有无解:
bool dfs(){ //参数用来表示状态
if n is a leaf node {
if the leaf is a goal node, return true
else return false
} else {
for each child c of n {
if solve(c) succeeds, return true
}
return false
}
}
有多少个解:
void solve(Node n) {
if n is a leaf node {
if the leaf is a goal node, count++, return;
else return
} else {
for each child c of n {
solve(c)
}
}
}
最好的解:
void solve(Node n) {
if n is a leaf node {
if the leaf is a goal node, update best result, return;
else return
} else {
for each child c of n {
solve(c)
}
}
}
一个例子(1到n的n位数全排列):
//回溯法 全排列
//从1-n的 n位数全排列
void dfs(int*res, int*visit, int step, int n){
if(step == n){
for(int i=0;i<n;i++){
cout<<res[i];
}
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(visit[i] ==0){
res[step] = i;
visit[i] = 1;
dfs(res,visit,step+1,n);
visit[i] = 0;
}
}
}
-回溯法&spm=1001.2101.3001.5002&articleId=90277872&d=1&t=3&u=2e77af27b4834de697a5d844d3020411)
654

被折叠的 条评论
为什么被折叠?



