C++ 做一个c++;11 Dijkstra实现返回最短路径

C++ 做一个c++;11 Dijkstra实现返回最短路径,c++,algorithm,c++11,dijkstra,C++,Algorithm,C++11,Dijkstra,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 sou

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;
}
struct-edge
{
边(常数到,常数到):到(\u到),长度(\u到)
{
}
int到;
整数长度;
};
int dijkstra(常量向量<向量>&图形,int源,int目标){
向量最小距离(graph.size(),INT_MAX);
最小距离[源]=0;
设置活动的\u顶点;
活动顶点。插入({0,source});
而(!active_texts.empty()){
int其中=活动顶点。begin()->秒;
if(其中==目标)返回最小距离[where];
活动顶点。擦除(活动顶点。开始());
对于(自动编辑:图形[其中])
if(最小距离[ed.to]>最小距离[where]+ed.length){
活动顶点。擦除({min_距离[ed.to],ed.to});
最小距离[ed.to]=最小距离[where]+ed.length;
活动顶点。插入({min_距离[ed.to],ed.to});
}
}
返回INT_MAX;
}
int main()
{
向量节点0{边(1,1),边(3,7),边(2,1)};
向量节点1{边(0,1),边(2,2),边(3,4)};
向量节点2{边(1,2),边(3,3),边(0,1)};
向量节点3{边(2,3),边(0,7),边(1,4)};
向量图{node0,node1,node2,node3};
int r=dijkstra(图,0,3);
返回0;
}

您可以通过创建“家长”列表使其返回最短路径。基本上,此列表将保存跟踪的每个顶点的父对象。所谓父节点,我的意思是,对于任何顶点,该顶点的父节点是最短路径中它前面的节点。更新“最小距离”列表时,还应通过将顶点的父对象“ed.to”设置为“where”来更新“parents”列表。然后,您可以返回父列表并跟踪它以找到最短路径。只需访问目标节点的父节点,并按顺序移动,直到找到父节点为源节点的节点。这是您的路径。

您可以通过创建“家长”列表使其返回最短路径。基本上,此列表将保存跟踪的每个顶点的父对象。所谓父节点,我的意思是,对于任何顶点,该顶点的父节点是最短路径中它前面的节点。更新“最小距离”列表时,还应通过将顶点的父对象“ed.to”设置为“where”来更新“parents”列表。然后,您可以返回父列表并跟踪它以找到最短路径。只需访问目标节点的父节点,并按顺序移动,直到找到父节点为源节点的节点。这就是您的路径。

而不是返回:

从目标开始,检查所有边指向目标的节点。拾取与目标节点相邻的节点,该节点与目标节点的最小距离+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;
}
struct-edge
{
int到;
整数长度;
};
使用node=std::vector;
使用graph=std::vector;
void add_edge(图形&g、整数开始、整数结束、整数长度){
如果((int)g.size()活动顶点;
活动顶点。插入({0,source});
而(!active_texts.empty()){
int其中=活动顶点。begin()->秒;
如果(其中==目标)
{
int cost=最小距离[其中];
//std::cout而不是返回:

从目标节点开始,检查所有边缘指向目标节点的节点。选择与目标节点相邻且与目标节点的最小距离+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;
}
struct-edge
{
int到;
整数长度;
};
使用node=std::vector;
使用graph=std::vector;
void add_edge(图形&g、整数开始、整数结束、整数长度){
如果((int)g.size()活动顶点;
活动顶点。插入({0,source});
而(!active_texts.empty()){
int其中=活动顶点。begin()->秒;
如果(其中==目标)
{
int cost=最小距离[其中];

//std::难道它似乎有什么问题吗?@madhatter现在看看编辑。这对我来说很好。如果你不能运行这个,那么我不知道我是否可以帮助你。在我的示例中,从0到2的路径应该是0,2。而不是0,1,3。它似乎有什么问题吗?@madhatter现在看看编辑。这对我来说很好。如果你不能运行我不知道我是否能帮到你。在我的例子中,从0到2的路径应该是0,2,而不是0,1,3。