How to Pass Direceted Graph (adjacency list) into Dijkstra Algorithm Boost to find shortest path?

喜夏-厌秋 提交于 2020-02-16 04:06:23

问题


I have written this Class as a start to build My Algorithm, but I can see Before word on console, but not After ! what is my mistake in using Dijkstra Algorithm of Boost ??

#include <myalgorithm.h>
#include<mygraphbuilder.h>
//===============================================
using namespace std;
using namespace boost;
//===============================================

MyAlgorithm::MyAlgorithm()// Default constructor
{
}
//===========================================================================
MyAlgorithm::MyAlgorithm(graph_t AnyGraph, Vertex VSource){//}, Vertex VTarget){ // Parameters Constructor

  MyGraph = AnyGraph;
  vector<Vertex> p(num_vertices(AnyGraph));
  vector<double> d(num_edges(AnyGraph));
  //===========================================================================
  //Dijkstra_Algorithm
  //===========================================================================
  cout<<"Before\t"<<endl;
  dijkstra_shortest_paths(AnyGraph, VSource,
                          predecessor_map(boost::make_iterator_property_map(p.begin(), get(boost::vertex_index, AnyGraph))).
                          distance_map(boost::make_iterator_property_map(d.begin(), get(boost::vertex_index, AnyGraph))));
 cout<<"After\t"<<endl;
  //===========================================================================
}// End of Parameters Constructor
//===========================================================================
MyAlgorithm::~MyAlgorithm(){ //Destructur
}
//===========================================================================
// Accessors
// function to call ShortPath
vector <Vertex> MyAlgorithm::getShortPath(){
  return MyAlgorithm::ShortPath;
}
// function to call the Graph
graph_t MyAlgorithm::getGraph(){
  return MyGraph;
}
//===========================================================================
// Mutators
//function to set short path Vector as whole
void MyAlgorithm::setShortPath(vector<Vertex> PathVector){
  MyAlgorithm::ResetShortPath();
  MyAlgorithm::ShortPath = PathVector;
}
//function to inject node to Short Path
void MyAlgorithm::setShortPath(Vertex MyNode){
  ShortPath.emplace_back(MyNode);
}
// function to set a graph
void MyAlgorithm::setGraph(graph_t YourGraph){
  MyGraph = YourGraph;
}
//============================================================================
//function to reset short path
void MyAlgorithm::ResetShortPath(){
  MyAlgorithm::ShortPath.clear();
}
//function to Print Out Results
void MyAlgorithm::PrintOut(){
  cout << "distances and parents:" << endl;
  graph_traits < graph_t >::vertex_iterator vi, vend;
  for (boost::tie(vi, vend) = vertices(MyAlgorithm::MyGraph); vi != vend; ++vi) {
      vector<Vertex> p(num_vertices(MyAlgorithm::MyGraph));
      vector<double> d(num_vertices(MyAlgorithm::MyGraph));
      cout << "distance(" << *vi << ") = " << d[*vi] << ", ";
      cout << "parent(" << *vi << ") = " << p[*vi] << endl;
    } // End of Print Loop
}// end of Print Function

My Graph is defined as following :

typedef adjacency_list < vecS, vecS, directedS, property < vertex_name_t, idType >, property < edge_weight_t, double > > graph_t;

Where idType is unsigned long long int; but it didn't work, how I can Make it work ??


回答1:


I don't see what the question is. Your code would simply compile, see Live On Coliru.

That said

  • you can probably do without copying the graph quite so many times
  • you should make the distance-map to number of vertices instead of edges:

    std::vector<double> d(num_edges(MyGraph));
    

    is supposed to be

    std::vector<double> d(num_vertices(MyGraph));
    

UPDATE

To the added code in the question:

  • Like I said, you probably should not be copying quite so much. In particular, why does MyAlgorithm own a copy of AnyGraph as a member MyGraph? It is never used by your own constructor...

  • Similarly, the added code has the same problem, specifically with

    for (auto v : make_iterator_range(vertices(MyGraph))) {
        std::vector<Vertex> p(num_vertices(MyGraph));
        std::vector<double> d(num_vertices(MyGraph));
        std::cout << "distance(" << v << ") = " << d[v] << ", ";
        std::cout << "parent(" << v << ") = " << p[v] << std::endl;
    }
    

    The d and p vectors are simply created with default-initialized values every iteration through the loop. What did you expect to find?

  • I can guess that you intended the result of dijkstra_shortest_paths to be used there, but you never did anything to make that happen. At the very least it looks like you should have made d and p member varlables

  • The setShortPath member functions are never used. By extension, the ShortPath member is never properly set. It seems you are aware of this because you also don't attempt to use it in PrintOut

  • There is a conceptual problem with printing "The Shortest Path" as it obviously depends on the target vertex... I'd write a getShortPath accessor that calculates a specific path:

    Path getShortPath(Vertex destination) {
        Path path;
    
        while (destination != MyGraph.null_vertex()) {
            path.push_front(destination);
            if (destination == src)
                return path;
    
            if (predecessors.at(destination) == destination)
                break;
            destination = predecessors.at(destination);
        }
        throw std::runtime_error("Unreachable");
    }
    
  • Now you can add a print function for any path:

    void PrintPath(MyAlgorithm::Path const& path, graph_t const& g) {
        std::cout << "Path: ";
        auto idmap = get(boost::vertex_name, g);
        auto wmap = get(boost::edge_weight, g);
    
        auto previous = g.null_vertex();
        for (auto v : path) {
            if (previous != g.null_vertex()) {
                for (auto e : make_iterator_range(out_edges(previous, g))) {
                    if (target(e, g) == v) {
                        std::cout << " -> (w:" << " << " << wmap[e] << ") ";
                    }
                }
            }
            std::cout << "#" << v << " (id:" << idmap[v] << ") ";
            previous = v;
        }
        std::cout << "\n";
    }
    

    It also prints weights on every edge (you will see it matches the total distance)

Fixed Demo

Here's a version that fixes all of the above. I stopped generating random graphs as now the "test cases" make assumptions about which paths are reachable:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dag_shortest_paths.hpp>
#include <boost/graph/graph_utility.hpp>
#include <iostream>

using boost::make_iterator_range;

using idType = unsigned long long;

typedef boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::directedS,
    boost::property<boost::vertex_name_t, idType>,
    boost::property<boost::edge_weight_t, double>> graph_t;

struct MyGraphBuilder {
    void generate();
    void printGraph() const;

    graph_t const& getGraph() const { return MyGraph; }
    graph_t&       getGraph()       { return MyGraph; }
  private:
    graph_t MyGraph;
};

void MyGraphBuilder::printGraph() const {
    std::cout << "Number of Vertices is:" << num_vertices(MyGraph) << "\n";
    std::cout << "Number of Edges is:" << num_edges(MyGraph) << "\n";

    boost::print_graph(MyGraph, boost::get(boost::vertex_name, MyGraph), std::cout);

    // to print with edge weights:
    for (auto v : make_iterator_range(vertices(MyGraph))) {
        for (auto oe : make_iterator_range(out_edges(v, MyGraph))) {
            std::cout << "Edge " << oe << " weight " << get(boost::edge_weight, MyGraph, oe) << "\n";
        }
    }
}

void MyGraphBuilder::generate() {
    MyGraph = graph_t(5); // clear graph, 5 vertices

    auto idmap = get(boost::vertex_name, MyGraph);
    idmap[0] = 0ull;
    idmap[1] = 100ull;
    idmap[2] = 200ull;
    idmap[3] = 300ull;
    idmap[4] = 400ull;

    add_edge(1, 3, { 1.52275 }, MyGraph);
    add_edge(2, 0, { 8.79559 }, MyGraph);
    add_edge(2, 0, { 6.41004 }, MyGraph);
    add_edge(3, 2, { 7.37265 }, MyGraph);
    add_edge(4, 0, { 1.18526 }, MyGraph);
}

struct MyAlgorithm {
    using Vertex = graph_t::vertex_descriptor;

    graph_t MyGraph;
    Vertex src;
    std::vector<Vertex> predecessors;
    std::vector<double> distances;

    MyAlgorithm(graph_t const& AnyGraph, Vertex VSource)
        : MyGraph(AnyGraph),
          src(VSource),
          predecessors(num_vertices(MyGraph)),
          distances(num_vertices(MyGraph))
    {
        dijkstra_shortest_paths(MyGraph, src,
                predecessor_map(make_iterator_property_map(predecessors.begin(), get(boost::vertex_index, MyGraph)))
                .distance_map(boost::make_iterator_property_map(distances.begin(), get(boost::vertex_index, MyGraph))));
    }

    using Path = std::deque<Vertex>;
    Path getShortPath(Vertex destination) {
        Path path;

        while (destination != MyGraph.null_vertex()) {
            path.push_front(destination);
            if (destination == src)
                return path;

            if (predecessors.at(destination) == destination)
                break;
            destination = predecessors.at(destination);
        }
        throw std::runtime_error("Unreachable");
    }

    void PrintRawData() const {
        std::cout << "distances and parents:" << std::endl;
        for (auto v : make_iterator_range(vertices(MyGraph))) {
            std::cout << "distance(" << v << ") = " << distances.at(v) << ", ";
            std::cout << "parent(" << v << ") = " << predecessors.at(v) << std::endl;
        }
    }

    graph_t const& getGraph() const { return MyGraph; }
    graph_t&       getGraph()       { return MyGraph; }
};

void PrintPath(MyAlgorithm::Path const& path, graph_t const& g) {
    std::cout << "Path: ";
    auto idmap = get(boost::vertex_name, g);
    auto wmap = get(boost::edge_weight, g);

    auto previous = g.null_vertex();
    for (auto v : path) {
        if (previous != g.null_vertex()) {
            for (auto e : make_iterator_range(out_edges(previous, g))) {
                if (target(e, g) == v) {
                    std::cout << " -> (w:" << " << " << wmap[e] << ") ";
                }
            }
        }
        std::cout << "#" << v << " (id:" << idmap[v] << ") ";
        previous = v;
    }
    std::cout << "\n";
}

int main() {
    MyGraphBuilder builder;
    builder.generate();
    //builder.printGraph();

    MyAlgorithm algo(builder.getGraph(), 1); // 1 is first vertex, not idmap

    algo.PrintRawData();

    auto p0 = algo.getShortPath(0);
    auto p1 = algo.getShortPath(1);
    auto p2 = algo.getShortPath(2);
    auto p3 = algo.getShortPath(3);

    for (auto path : {p0, p1, p2, p3}) {
        PrintPath(path, algo.getGraph());
    }

    // vertex 4 is unreachable:
    try {
        auto p4 = algo.getShortPath(4);
    } catch(std::exception const& e) {
        std::cout << "Error getting path for vertex 4: " << e.what() << "\n";
    }
}

Prints

distances and parents:
distance(0) = 15.3054, parent(0) = 2
distance(1) = 0, parent(1) = 1
distance(2) = 8.8954, parent(2) = 3
distance(3) = 1.52275, parent(3) = 1
distance(4) = 1.79769e+308, parent(4) = 4
Path: #1 (id:100)  -> (w: << 1.52275) #3 (id:300)  -> (w: << 7.37265) #2 (id:200)  -> (w: << 8.79559)  -> (w: << 6.41004) #0 (id:0) 
Path: #1 (id:100) 
Path: #1 (id:100)  -> (w: << 1.52275) #3 (id:300)  -> (w: << 7.37265) #2 (id:200) 
Path: #1 (id:100)  -> (w: << 1.52275) #3 (id:300) 
Error getting path for vertex 4: Unreachable


来源:https://stackoverflow.com/questions/59009846/how-to-pass-direceted-graph-adjacency-list-into-dijkstra-algorithm-boost-to-fi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!