【问题标题】:Make a c++11 Dijkstra Implementation return shortest Path使 c++11 Dijkstra 实现返回最短路径
【发布时间】:2017-05-28 23:02:34
【问题描述】:

Michal Forisek 的 Dijkstra 算法的 C++11 实现确实可以非常快速且优雅地计算最短距离,而无需太多代码。但是我怎样才能返回路径呢?

struct edge
{
    edge(const int _to, const int _len): to(_to), length(_len)
    {

    }

    int to;
    int length;
};

int dijkstra(const vector< vector<edge> > &graph, int source, int target) {
    vector<int> min_distance( graph.size(), INT_MAX );
    min_distance[ source ] = 0;
    set< pair<int,int> > active_vertices;
    active_vertices.insert( {0,source} );

    while (!active_vertices.empty()) {
        int where = active_vertices.begin()->second;
        if (where == target) return min_distance[where];
        active_vertices.erase( active_vertices.begin() );
        for (auto ed : graph[where]) 
            if (min_distance[ed.to] > min_distance[where] + ed.length) {
                active_vertices.erase( { min_distance[ed.to], ed.to } );
                min_distance[ed.to] = min_distance[where] + ed.length;
                active_vertices.insert( { min_distance[ed.to], ed.to } );
            }
    }
    return INT_MAX;
}

int main()
{

    std::vector<edge> node0 {edge(1,1), edge (3,7), edge (2,1)};
    std::vector<edge> node1 {edge(0,1), edge (2,2), edge (3,4)};
    std::vector<edge> node2 {edge(1,2), edge (3,3), edge (0,1)};
    std::vector<edge> node3 {edge(2,3), edge (0,7), edge (1,4)};

    std::vector<std::vector<edge>> graph {node0, node1, node2, node3};

    int r = dijkstra(graph, 0, 3);

return 0;
}

【问题讨论】:

    标签: c++ algorithm c++11 dijkstra


    【解决方案1】:

    您可以通过创建“父母”列表使其返回最短路径。基本上,此列表将包含您跟踪的每个顶点的父级。通过父节点,我的意思是对于任何顶点,该顶点的父节点是最短路径中它之前的节点。当您更新 min_distance 列表时,您还应该通过将顶点“ed.to”的父级设置为“where”来更新“parents”列表。然后您可以返回父母列表并通过它来查找最短路径。只需访问目标节点的父节点,然后按顺序移动,直到找到其父节点为源的节点。这就是你的道路。

    【讨论】:

    • 它似乎有什么问题?
    • @madhatter 立即查看编辑。这对我来说很好。如果你不能运行这个,那么我不知道我是否可以帮助你。
    • 在我的示例中从 0 到 2 的路径应该是 0,2。不是 0,1,3。
    【解决方案2】:

    而不是返回:

    从目的地开始,检查所有有边的节点。选择与目标相邻的节点,到目标节点的最小距离+ed.length 最短。如果相邻节点不在最小距离图中,则忽略它。

    这是您的新目的地。重复,直到您的目的地成为您的来源。

    基本上你可以贪婪地回到起点,因为你知道哪个节点最便宜。

    如果你的边是双向的,或者你有办法向后查找边,这很便宜。

    否则,在最小距离图中跟踪您来自的最小距离 节点可以让您轻松完成。

    struct edge
    {
      int to;
      int length;
    };
    
    using node = std::vector<edge>;
    using graph = std::vector<node>;
    void add_edge( graph& g, int start, int finish, int length ) {
      if ((int)g.size() <= (std::max)(start, finish))
        g.resize( (std::max)(start,finish)+1 );
      g[start].push_back( {finish, length} );
      g[finish].push_back( {start, length} );
    }
    
    using path = std::vector<int>;
    
    struct result {
      int distance;
      path p;
    };
    result dijkstra(const graph &graph, int source, int target) {
      std::vector<int> min_distance( graph.size(), INT_MAX );
      min_distance[ source ] = 0;
      std::set< std::pair<int,int> > active_vertices;
      active_vertices.insert( {0,source} );
    
      while (!active_vertices.empty()) {
        int where = active_vertices.begin()->second;
        if (where == target)
        {
          int cost = min_distance[where];
          // std::cout << "cost is " << cost << std::endl;
          path p{where};
          while (where != source) {
            int next = where;
            for (edge e : graph[where])
            {
              // std::cout << "examine edge from " << where << "->" << e.to << " length " << e.length << ":";
    
              if (min_distance[e.to] == INT_MAX)
              {
                // std::cout << e.to << " unexplored" << std::endl;
                continue;
              }
    
              if (e.length + min_distance[e.to] != min_distance[where])
              {
                // std::cout << e.to << " not on path" << std::endl;
                continue;
              }
              next = e.to;
              p.push_back(next);
              // std::cout << "backtracked to " << next << std::endl;
              break;
            }
            if (where==next)
            {
              // std::cout << "got lost at " << where << std::endl;
              break;
            }
            where = next;
          }
          std::reverse( p.begin(), p.end() );
          return {cost, std::move(p)};
        }
        active_vertices.erase( active_vertices.begin() );
        for (auto ed : graph[where]) 
          if (min_distance[ed.to] > min_distance[where] + ed.length) {
            active_vertices.erase( { min_distance[ed.to], ed.to } );
            min_distance[ed.to] = min_distance[where] + ed.length;
            active_vertices.insert( { min_distance[ed.to], ed.to } );
          }
      }
      return {INT_MAX};
    }
    
    int main()
    {
      graph g;
      add_edge(g, 0, 1, 1);
      add_edge(g, 0, 3, 7);
      add_edge(g, 0, 2, 1);
      add_edge(g, 1, 2, 2);
      add_edge(g, 1, 3, 4);
      add_edge(g, 2, 3, 3);
    
    
      auto r = dijkstra(g, 0, 3);
      std::cout << "cost is " << r.distance << ": ";
      for (int x:r.p) {
        std::cout << x << " then ";
      }
      std::cout << "and we are done.\n";
    
      return 0;
    }
    

    Live example.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      • 2020-11-15
      • 2013-01-08
      • 1970-01-01
      • 2015-05-19
      • 1970-01-01
      相关资源
      最近更新 更多