如何在Scala中停止回溯?

时间:2012-01-19 17:54:26

标签: scala functional-programming backtracking

假设我正在使用回溯解决问题(例如N-Queen)。如果我想找到唯一的(第一个)解决方案而不是全部解决方案,该怎么办?

我想我可以强制执行(例如使用可变的布尔标志)。我想知道我是如何做到的功能

3 个答案:

答案 0 :(得分:14)

虽然Scala的Option可以在这里工作,正如其他两个答案所指出的那样,更惯用的功能方法是使用Scala中的“懒惰列表” - 或Stream来表示一套解决方案。

我发现自己编写了这样的代码,例如:

trait Node[A] {
  def children: Stream[A with Node[A]]

  def dfs(f: A => Boolean): Stream[A] = this.children.flatMap {
    child => if (f(child)) Stream(child) else child.dfs(f)
  }
}

现在假设我有一个扩展Board的{​​{1}}类,并且具有Node[Board]方法的实现,该方法返回所有有效的板,另外还有一块。假设它还有一些其他有用的东西,比如children方法,带size的伴随对象等。

然后,我可以编写以下内容以获得empty解决方案:

Stream

val solutions = Board.empty.dfs(_.size == 8) 是懒惰的,只评估它的头部,所以现在我们只搜索了足够远的树来找到第一个解决方案。我们可以使用Stream

来获得此解决方案
head

或者其他什么。但如果我需要,我也可以得到其他结果:

scala> solutions.head
res1: Board = 
o . . . . . . .
. . . . o . . .
. . . . . . . o
. . . . . o . .
. . o . . . . .
. . . . . . o .
. o . . . . . .
. . . o . . . .

这会搜索足够多的树以找到第十个解决方案,然后停止。

scala> solutions(10) res2: Board = . o . . . . . . . . . . . . o . . . . . o . . . . . . . . . . o o . . . . . . . . . . o . . . . . . . . . o . . . . o . . . . . 优于Stream方法的一大优势是,如果我需要它,我可以获得额外的结果,而不需要为第一个付出更多。

答案 1 :(得分:5)

这是一个简单的情况,深度优先搜索在找到它正在寻找的内容时停止。它使用了Option,如Chris K的答案所述。

case class Tree[A](v: A, subtrees: Tree[A]*) {
  def dfs(s: A): Option[A] = {
    println("visiting " + v)
    subtrees.foldLeft(if(v == s) Some(v) else None)((r, t) => 
      if(r.isDefined) 
        r 
      else 
        t.dfs(s)
    )
  }
  override def toString() = "Tree(%s%s%s)".format(v, if(subtrees.nonEmpty) ", " else "", subtrees.mkString(", "))
}

用法:

scala> val t = Tree(1, Tree(2, Tree(3), Tree(4)), Tree(5, Tree(6), Tree(7)))
t: Tree[Int] = Tree(1, Tree(2, Tree(3), Tree(4)), Tree(5, Tree(6), Tree(7)))

t看起来像

     1
   /   \
  2     5
 / \   / \
3   4 6   7    

因此,我们可以搜索元素并跟踪它访问的节点:

scala> t.dfs(6)
visiting 1
visiting 2
visiting 3
visiting 4
visiting 5
visiting 6
res42: Option[Int] = Some(6)

请注意,在找到我们正在寻找的内容后,我们不再访问任何节点。

答案 2 :(得分:2)

假设您正在使用递归搜索功能,您的函数应该返回结果(即皇后的定位)或者指示找不到该分支的结果。 Scala可能有一个选项/类型,你可以使用它。该建议同样适用于任何功能语言。