算法导论:回溯法
基本思想
将所有的解按照一定结构排列,再进行搜索。一般解空间构造成树状结构,用深度优先搜索策略。
- 针对所给问题,定义问题的解空间。
- 确定易于搜索的解空间结构。
- 以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
常用的剪枝函数:
- 用约束函数在扩展结点处剪去不满足约束的子树。
- 用限界函数剪去得不到最优解的子树。
如果解空间树中从根结点到叶结点的最长路径的长度为
N 皇后问题
问题描述
在
:显然成立 :问题无解 :可能存在多个解
四皇后解空间
向量
完全四叉树的所有叶子节点构成一个解空间,每个叶子节点就是一个可能解,满足要求的叶子节点就是可行解。
生成问题状态
- 扩展结点:一个正在产生儿子的结点
- 活结点:一个自身已生成但其儿子还没有全部生成的节点
- 死结点:一个所有儿子都已经产生的结点
- 深度优先的问题状态生成法:如果对一个扩展结点
,一旦产生了它的一个儿子 ,就把 当做新的扩展结点。在完成对子树 的穷尽搜索之后,将 重新变成扩展结点,继续生成 的下一个儿子(如果存在) - 宽度优先的问题状态生成法:在一个扩展结点变成死结点之前,它一直是扩展结点,为了避免生成那些不可能产生最佳解的问题状态,要不断地利用限界函数来处死那些实际上不可能产生所需解的活结点,以减少问题的计算量
四皇后状态空间树
- 四皇后状态空间树是 4 叉完全树
- 约束方程:
- 基本条件:
- 不在同一行:
- 不在同一列:
- 不在同一个斜线:
- 基本条件:
伪代码
// 判断接下来的扩展节点是否符合要求
Boolean place(int k) {
for(int i = 1; i < k; i++) {
if((abs(k-j) == abs(x[j]-x[k])) || (x[j] == x[k])) return false;
}
return true;
}
// 回溯法,n 表示n皇后
void backTrack(int t) {
if(t > n) return;
else {
for(int i = 1; i <= n; i++) {
x[t] = i;
if(place(t)) backTrack(t+1);
}
}
}
回溯法
递归回溯
void backTrack(int t) {
// 到达叶子节点,也就是一个可行解
if(t > n) output(x);
else {
for(int i = f(n,t); i <= g(n,t); i++) {
x[t] = h(i);
if(constraint(t) && bound(t)) backTrack(t+1);
}
}
}
迭代回溯
void iterativeBacktrack() {
int t = 1;
while(t > 0) {
if(f(n,t) <= g(n,t)) {
for(int i = f(n,t); i <= g(n,t); i++) {
x[t] = h(i);
if(constraint(t) && bound(t)) {
if(solution(t)) output(x);
else t++;
}
}
}
else t--;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步