【问题标题】:Adjacency-List Paths in ScalaScala中的邻接列表路径
【发布时间】:2018-06-30 10:43:32
【问题描述】:

如果我有一个邻接列表,在 Scala 中表示如下:

val l = List(
    List((1, 1), (2, 3), (4, 10)),
    List((2, 1)),
    List((3, 1), (4, 5)),
    List(4, 1)),
    List())

每个“列表”都包含有向图中从一个节点到另一个节点的路径成本。所以第一个包含三个条目的“列表”代表第一个节点的后继节点(从 0 开始计数)。这意味着节点 0 以 1 的成本定向到节点 1,以 3 的成本定向到节点 2,以 10 的成本定向到节点 4,依此类推。

如果存在从给定节点到另一个节点的最大成本路径,如何递归计算?我想到了这样的事情:

def hasMaxCostPath: (List[List[(Int, Int)]], Int, Int, Int) => Int => Boolean = (adj, from, to, max) => len =>

所以函数接收邻接列表“adj”、起始节点“from”、结束节点“to”、路径的最大成本“max”和路径的最大长度“len”。 所以我认为根据上面给出的邻接列表,结果应该如下:

hasMaxCostPath(l, 0, 2, 2)(1) == false
hasMaxCostPath(l, 0, 2, 3)(1) == true

此外,如何递归计算在给定最大长度内从一个指定节点到另一个节点的所有路径成本的列表?可能是这样的:

def getPaths: (List[List[(Int, Int)]], List[(Int, Int)], Int, Int) => List[Int] =
(adj, vn, dest, len) =>

所以这个函数会得到邻接列表“adj”,一个已经访问过的节点列表“vn”和(节点,成本),其中我们将给定节点作为起始节点,目标节点“dest”和路径“len”的最大长度。对于这个函数,结果可能如下所示:

getPaths(l, List((0, 0)), 2, 1) == List(3)     // Node0 -> Node2
getPaths(l, List((0, 0)), 2, 2) == List(2, 3)  // Node0 -> Node1 -> Node2 AND Node0 -> Node2

抱歉,我对 Scala 很陌生

【问题讨论】:

  • 我在这个问题中看不到任何 scala 特定的问题。看起来更像是您没有尝试实现的相当基本的图形算法列表。请展示您到目前为止尝试过的内容,并解释您到底在哪里卡住了。如果您不知道如何开始,请阅读任何本关于图算法的介绍性书籍。顺便说一句:与 Haskell 不同,在 Scala 中以您在问题中使用的无名完全柯里化形式声明函数并不常见。改为使用带有正确参数名称的普通方法签名。
  • 这是作业:-) 吗?

标签: algorithm scala path-finding directed-graph adjacency-list


【解决方案1】:

这对你有用吗?

package foo

object Foo {

  def main(args: Array[String]): Unit = {
    val edges = List(
      List((1, 1), (2, 3), (4, 10)),
      List((2, 1)),
      List((3, 1), (4, 5)),
      List((4, 1)),
      List())
    println(hasMaxCostPath(edges,0,1,2))
    println(hasMaxCostPath(edges,0,2,2))
  }

  def hasMaxCostPath(edges: List[List[(Int, Int)]], start: Int, end: Int, maxCost: Int): Boolean = {
    maxCost > 0 &&
    edges(start).exists(a =>
      (a._1 == end && a._2 <= maxCost) ||
      hasMaxCostPath(edges, a._1, end, maxCost - a._2)
    )
  }

}

编辑:====

上述方案没有考虑长度参数。 这是一个带有长度参数的解决方案:

package foo

object Foo {

  def main(args: Array[String]): Unit = {
    val edges = List(
      List((1, 1), (2, 3), (4, 10)),
      List((2, 1)),
      List((3, 1), (4, 5)),
      List((4, 1)),
      List())
      assert(! hasMaxCostPath(edges,0,4,4,3))
      assert(hasMaxCostPath(edges,0,4,4,4))
  }

  def hasMaxCostPath(edges: List[List[(Int, Int)]], start: Int, end: Int, maxCost: Int, maxLength: Int): Boolean = {
    maxLength > 0 &&
    maxCost >= 0 &&
    edges(start).exists(a =>
      (a._1 == end && a._2 <= maxCost) ||
      hasMaxCostPath(edges, a._1, end, maxCost - a._2, maxLength - 1)
    )
  }

}

=== 编辑:

这是一个解决方案,包括您的第二个问题:

package foo

object Foo {

  def main(args: Array[String]): Unit = {
    val edges = List(
      List((1, 1), (2, 3), (4, 10)),
      List((2, 1)),
      List((3, 1), (4, 5)),
      List((4, 1)),
      List())
    assert(! hasMaxCostPath(edges,0,4,4,3))
    assert(hasMaxCostPath(edges,0,4,4,4))
    assert(getMaxCostPaths(edges,0,0,5,5) == List())
    assert(getMaxCostPaths(edges,0,1,1,1) == List(List(0,1)))
    assert(getMaxCostPaths(edges,0,2,2,2) == List(List(0,1,2)))
    assert(getMaxCostPaths(edges,0,2,5,5) == List(List(0,2), List(0,1,2)))
  }

  def hasMaxCostPath(edges: List[List[(Int, Int)]], start: Int, end: Int, maxCost: Int, maxLength: Int): Boolean = {
    maxLength > 0 &&
    maxCost >= 0 &&
    edges(start).exists(a =>
      (a._1 == end && a._2 <= maxCost) ||
      hasMaxCostPath(edges, a._1, end, maxCost - a._2, maxLength - 1)
    )
  }

  def getMaxCostPaths(
         edges: List[List[(Int, Int)]],
         from: Int, to: Int,
         maxCost: Int,
         maxLength: Int): List[List[Int]] = {
      getMaxCostPathsRec(edges, from, to, maxCost, maxLength, List(from))
  }

  def getMaxCostPathsRec(
         edges: List[List[(Int, Int)]],
         start: Int, end: Int,
         maxCost: Int,
         maxLength: Int,
         path: List[Int]) : List[List[Int]] = {
    if (maxLength <= 0 || maxCost < 0) return List()
    val direct = edges(start).filter(a => a._1 == end && a._2 <= maxCost).map(edge => path ::: List(edge._1))
    val transitive = edges(start).flatMap(a =>
      getMaxCostPathsRec(edges, a._1, end, maxCost - a._2, maxLength - 1, path ::: List(a._1))
    )
    direct ::: transitive
  }

}

【讨论】:

  • 非常感谢,工作就像一个魅力。对第二个 def“getPaths”有什么想法吗?
  • 为此部分添加了解决方案。
  • 非常感谢。对于第二个问题,我不需要 maxCost,只需要 maxLength 以及如何通过最初使用“访问的节点”参数(正如我在问题中所述)来做到这一点,这也节省了路径的成本,而不是“路径”参数?
  • 但是函数的返回类型是一个列表,仅列出从开始节点到结束节点的所有可能路径的成本
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多