问题
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 ofAnyGraph
as a memberMyGraph
? 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
andp
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 maded
andp
member varlablesThe
setShortPath
member functions are never used. By extension, theShortPath
member is never properly set. It seems you are aware of this because you also don't attempt to use it inPrintOut
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