DAG algorithm

shortest path s-> all other nodes

× negative cycles (no shortest path)

  • bellmanford 

with negative weights

proof: 图中路径 至多 有|v|-1  条边,否则有循环。在无负回路中,可不走此循环以减少距离。

通过对点 出边 的搜索,不断更新最短距离,直到所有点的出路都遍历过。

  • dijkstra

cannot work with negative weights

greedy

不断更新已遍历的点集合visited:{}。

 

topological sorting:

  1. is not unique
  2. build system, apt-get tool, which task proceed which one
  3. stack 放已经访问过的顶点。一顶点的出边全部遍历即为已访问。直到所有顶点访问结束。初始的unvisited点为随机选择。

implement in scala:

import scala.io._

class WeightedDigraph(val n: Integer) {
  case class Edge(from: Int, to: Int, weight: Long)

  val adj = Array.fill(n)(List.empty[Edge])

  var m = 0

  def addEdge(from: Int, to: Int, w: Long) = {
    adj(from) = Edge(from, to, w)::adj(from)
    m+=1
    this
  }

  // Using Dijkstra's algorithm
  def shortestDistances(s: Int) = {
    val heap = IndexedHeap[Long](n)

    def put(v: Int, w: Long) {
      heap.put(v+1, w)
    }

    def deleteMin = heap.deleteMin match { case IndexKeyPair(v, w) => IndexKeyPair(v-1, w) }

    def changeKey(v: Int, w: Long) { heap.changeKey(v+1, w) }

    def contains(v: Int) = heap.contains(v+1)

    def get(v: Int) = heap.get(v+1)

    val distances = Array.fill(n)(Long.MaxValue)
    distances(s) = 0

    (0 until n) foreach { v => put(v, if (v==s) 0 else Long.MaxValue)}

    while(!heap.isEmpty) {
      val pair = deleteMin
      val v = pair.index
      val weight = pair.key
      distances(v) = weight
      adj(v) filter { edge => contains(edge.to) } foreach { edge =>
        val newDist = distances(v) + edge.weight
        if (get(edge.to) > newDist)  changeKey(edge.to, newDist)
      }
    }

    distances
  }

  def floydWarshal: Either[Int, Array[Array[Long]]] = {
    var prev = Array.ofDim[Long](n, n)
    val current = Array.ofDim[Long](n, n)
    // Base case, budget is zero
    for (i <- 0 until n; j <- 0 until n) {
      prev(i)(j) = if (i == j) 0l
      else {
        adj(i).find(_.to == j).map(_.weight) getOrElse Long.MaxValue
      }
    }
    for (k <- 0 until n) {
      for (i <- 0 until n; j <- 0 until n) {
        val inherited = prev(i)(j)
        val part1 = prev(i)(k)
        val part2 = prev(k)(j)
        val composite = if(part1 == Long.MaxValue || part2 == Long.MaxValue) Long.MaxValue else part1 + part2
        current(i)(j) = math.min(inherited, composite)
        if (i == j && current(i)(j) < 0) return Left(i)
      }
      prev = current
    }
    Right(current)
  }

  def reversed: WeightedDigraph = {
    val r = WeightedDigraph(n)
    for(u <- 0 until n; edge <- adj(u)) {
      r.addEdge(edge.to, u, edge.weight)
    }
    r
  }

  def bellmanFord(start: Int) : Either[Int, Seq[Long]] = {
    var prev = Array.ofDim[Long](n)
    val current = Array.ofDim[Long](n)
    // Base case, length is zero
    for(v <- 0 until n) {
      prev(v) = if(v == start) 0l else Long.MaxValue
    }
    val r = reversed
    for(length <- 1 until n; v <- 0 until n) {
      val inherited = prev(v)
      val cd = r.adj(v).map  { edge =>
        if (prev(edge.to) == Long.MaxValue) Long.MaxValue else prev(edge.to) + edge.weight
      }.min
      current(v) = math.min(inherited, cd)
      prev = current
    }
    // Checking for negative cycles, if a path of length N is better then there's a negative cycle
    for(v <- 0 until n) {
      val inherited = prev(v)
      val cd = r.adj(v).map  { edge =>
        if (prev(edge.to) == Long.MaxValue) Long.MaxValue else prev(edge.to) + edge.weight
      }.min
      if(math.min(inherited, cd) < prev(v)) return Left(v)
    }
    Right(current.toSeq)
  }
}

object WeightedDigraph {
  def apply(n: Int) = new WeightedDigraph(n)

  def fromFile(filename: String) = {
    val lines = Source.fromFile(filename).getLines()
    val n = lines.next().split("\\s+")(0).toInt
    val wg = new WeightedDigraph(n)
    lines foreach { line =>
      line split "\\s+" match {
        case Array(u,v,w) => wg.addEdge(u.toInt - 1, v.toInt - 1, w.toInt)
      }
    }
    wg
  }
}

 

posted on 2017-09-23 18:05  satyrs  阅读(227)  评论(0编辑  收藏  举报

导航