繁体   English   中英

如何使用Dijkstra算法找到图中从顶点到另一个的最短路径

[英]How to find the shortest path from a vertex to other in a graph with a Dijkstra's algorithm

我正在开发一个TOP的项目,我应该做一个返回图形的两个顶点之间的最短路径的函数,但是我得到一个错误。 我该怎么做才能解决这个问题?

还没有,因为我是一个新手。

Graph类

class Vertex
  attr_accessor :value, :neighbors, :prev, :dist
  def initialize(value)
      @value = value
      @neighbors = []
      @prev = nil
      @dist = Float::INFINITY
  end

  def add_edge(adjacent_vertex)
      @neighbors << adjacent_vertex
  end
end

class Graph
  attr_reader :vertices
  def initialize
      @vertices = {}
      @dijkstra_source = nil
  end

  def add_vertex(vertex)
      @vertices[vertex.value] = vertex
  end

  def add_edge(vertex1, vertex2)
      @vertices[vertex1.value].add_edge(@vertices[vertex2])
      @vertices[vertex2.value].add_edge(@vertices[vertex1])
  end

  def dijkstra(source)
    return if @dijkstra_source == source
      unvisited = @vertices.values
      unvisited.each do |vertex|
          vertex.dist = Float::INFINITY
          vertex.prev = nil
      end
      @vertices[source].dist = 0
      until unvisited.empty?
          current_node = unvisited.min_by(&:dist)
          break if current_node.dist == Float::INFINITY
          unvisited.delete(current_node)
          current_node.neighbors.each do |v|
              neighbor = @vertices[v]
              if unvisited.include?(neighbor)
                  alt = current_node.dist + 1
                  if alt < neighbor.dist
                    neighbor.dist = alt
                    neighbor.prev = current_node 
                  end
              end
          end
      end
      @dijkstra_source = source
  end

  def find_shortest_path(source, target)
      dijkstra(source)
      path = []
      u = target
      while u
          path.unshift(u)
          u = @vertices[u].prev
      end
      return path
  end
end

我在哪里设置顶点

require_relative 'graph'

class Knight
  attr_reader :character, :graph
  def initialize
      @character = "♞"
      @possible_moves = nil
      @positions = Array.new(8) { Array.new(8, " ") }
      @move_set = [
                    [-1,-2],
                    [-2,-1],
                    [-2,+1],
                    [-1,+2],
                    [+1,+2],
                    [+2,+1],
                    [+2,-1],
                    [+1,-2]
                   ]
      @graph = generate_graph
      generate_edges
  end

  def generate_graph
    graph = Graph.new
      @positions.each_index do |x|
          @positions[x].each_index do |y|
              vertex = Vertex.new([x,y])
              graph.add_vertex(vertex)
          end
      end
      graph
  end

  def generate_edges
      @graph.vertices.each do |key, value|
          @move_set.each do |move|
              x = key[0] + move[0]
              y = key[1] + move[1]
              if (0..7).include?(x) && (0..7).include?(y)
                  vertex = [x,y]
                  value.add_edge(vertex) unless value.neighbors.include?(vertex)
              end
          end
      end
  end
end

knight = Knight.new
knight.generate_edges
p knight.graph.find_shortest_path([1,2],[2,3])

我期望一个数组存储在从源顶点([1,2])到目标顶点(2,3)的最短路径内。

但不是我得到的是NilClass错误

Traceback (most recent call last):
    1: from knight.rb:50:in `<main>'
/home/brito/the_odin_project/knight_moves/graph.rb:63:in `find_shortest_path': undefined method `prev' for nil:NilClass (NoMethodError)

问题是在尝试调用prev方法时,没有初始化( nil ),如错误消息中所示。

最近的可疑调用位于Graph#find_shortest_path 如果您从那里打印@vertices u ,您将看到在第二次迭代时, u成为Vertex实例 ,而@vertices原始值作为键。 解决方法是将u = @vertices[u].prevu = @vertices[u].prev.value以保持u原始值 (请注意第一个检查@vertices[u].prev地点。

总结:

def find_shortest_path(source, target)
  dijkstra(source)
  path = []
  u = target
  while u
    path.unshift(u)
    u = (@vertices[u].prev.value if @vertices[u].prev)
  end
  return path
end

此外,上面的代码将解决问题,代码不是ruby惯用; FWIW,我发布了惯用版。

我明白,这对你来说太多了不寻常的模式,但万一你有兴趣深入研究:

def find_shortest_path(source, target)
  dijkstra(source)

  loop.reduce([[], target]) do |(path, u), _|
    break path unless u
    [
      path << u,
      (@vertices[u].prev.value if @vertices[u].prev)
    ]
  end
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM