【发布时间】:2020-09-06 19:29:58
【问题描述】:
回溯搜索是一种众所周知的问题解决技术,它通过所有可能的变量分配组合来寻找有效的解决方案。通用算法被抽象成简洁的高阶函数:https://en.wikipedia.org/wiki/Backtracking
有些问题需要部分回溯,也就是说,它们混合了不知道的非确定性(有一个选择,这很重要,如果你弄错了,你必须回溯)和不关心非确定性(可以做出选择,这并不重要,也许重要的是你需要多长时间才能找到解决方案,而不是正确性其中,您不必回溯)。
考虑例如可以用the DPLL algorithm 解决的布尔可满足性问题。如果你试图用一般的回溯算法来表示它,结果不仅会通过所有 2^N 变量赋值(遗憾的是在一般情况下是必要的),而且所有 N!尝试变量的顺序(完全没有必要,而且效率极低)。
是否有用于部分回溯的通用算法?一个简洁的高阶函数,它为 don't-know 和 don't-care 选择提供函数参数?
【问题讨论】:
-
DPLL 真的会遍历变量的所有排列吗?我的印象是它在每一步都使用启发式方法选择了一些单个变量,然后尝试了两个分支以查看公式是否可以满足。如果两个分支都失败了,那么给定点的公式肯定不能满足,没有理由尝试不同的变量。
-
@templatetypedef 确实,DPLL 算法本身在这方面很好。但是,如果您从 DPLL 中去掉回溯部分,转而使用通用回溯算法(只为特定领域的部分提供参数)呢?一般的回溯算法不会表现得那么好;它将遍历变量的所有排列。 (从某种意义上说,它不会知道变序的选择是不需要回溯的那种选择。)
-
我不喜欢 Wikipedia 伪代码如何模拟具有两个不同函数的迭代器/惰性列表 - 与返回惰性搜索列表的函数相比,它更难实现有趣的分支启发式树子按顺序打开(即便如此,树探索策略的选择也会产生很大的不同,将深度优先搜索与深度优先的最佳回溯进行比较)。
-
我常用的概括最好的启发式方法是,最受约束的优先。特别是对于使用 DPLL 解决 SAT 问题,将子句减少为单元子句是一个巨大的胜利,因为它可以让你进行单元传播,所以我会启发式地关注最短的子句。这应该更快地给你单元子句。
-
但是,有许多免费的、高度优化的 SAT 求解器。除非这是一个学习练习,否则请考虑使用其中之一。
标签: algorithm search backtracking recursive-backtracking