我有一个奇怪的错误,我根本找不到.
我正在使用Boost Graph Library构建一个adjacency_list图,并将顶点列表填充到一个向量中.当我遍历矢量时,它将正确地打印出所有顶点,但是,当我运行算法时,例如Dijkstra的最短路径,最后一个顶点显示为空白.
例如:
Shortest path from C to R
C -> H = 55
H -> = 97
-> R = 56
Distance: 208
更糟糕的是,如果我编写一个简单的搜索来选择一个特定的顶点,那么矢量中的最后一个顶点再次成为问题,因为它表明它不存在.
std::string start_vertex;
bool valid = false;
std::cout << "Vertices:" << std::endl;
for (auto &i : _vertices) {
std::cout << i << " ";
}
std::cout << std::endl;
while (!valid) {
std::cout << "Enter starting vertex: ";
std::cin >> start_vertex;
for (auto &i : _vertices) {
if (i == start_vertex) {
valid = true;
break;
}
}
}
上面,当搜索问题顶点时,继续循环,而所有其他顶点正常工作.如前所述,顶点全部在通过其他方式迭代时打印出来.
最后,当上面的foreach循环运行时,第一个顶点是空白的.我想所有这些都是相关的,但我无法弄清楚我在这里做了什么.我很乐意提供更多代码,但了解我应该首先考虑的内容会很有帮助.
谢谢.
#include <fstream>
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/config.hpp>
#include <boost/algorithm/string.hpp>
#include <utility>
#include <vector>
#include <map>
int main(int , const char * argv[]) {
std::ifstream input(argv[1]);
typedef int Weight;
typedef boost::property<boost::vertex_name_t, std::string> VertexNameProperty;
typedef boost::property<boost::edge_weight_t, Weight> EdgeWeightProperty;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
VertexNameProperty, EdgeWeightProperty> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
typedef boost::property_map<Graph, boost::vertex_name_t>::type NameMap;
typedef boost::iterator_property_map<Vertex*, IndexMap, Vertex, Vertex&>
PredecessorMap;
typedef boost::iterator_property_map<Weight*, IndexMap, Weight, Weight&>
DistanceMap;
std::string line, vertex;
std::getline(input, line);
std::getline(input, line);
boost::char_separator<char> sep(",");
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tok(line, sep);
std::vector<std::string> _vertices;
for (auto &i : tok) {
_vertices.push_back(i);
}
Graph g(sizeof(_vertices));
std::map<std::string, Vertex> vertex_map;
for (auto &i : _vertices) {
vertex_map[i] = boost::add_vertex(std::string(i), g);
}
char c;
struct GraphParameters {
char vertex_one, vertex_two;
Weight edge_weight;
};
std::getline(input, line);
while (getline(input, line)) {
GraphParameters p;
std::istringstream iss(line);
iss >> c >> p.vertex_one >> c >> p.vertex_two >> c >> p.edge_weight >> c;
std::string v1, v2;
std::stringstream ss1 ,ss2;
ss1 << p.vertex_one;
ss1 >> v1;
ss2 << p.vertex_two;
ss2 >> v2;
boost::add_edge(vertex_map[v1], vertex_map[v2], p.edge_weight, g);
}
std::string start_vertex, end_vertex;
bool valid = false;
std::cout << "Vertices:" << std::endl;
for (auto &i : _vertices) {
std::cout << i << " ";
}
std::cout << std::endl;
while (!valid) {
std::cout << "Enter starting vertex: ";
std::cin >> start_vertex;
for (auto &i : _vertices) {
if (i == start_vertex) {
valid = true;
break;
}
}
}
while (valid) {
std::cout << "Enter ending vertex: ";
std::cin >> end_vertex;
for (auto &i : _vertices) {
if (i == end_vertex) {
valid = false;
break;
}
}
}
std::vector<Vertex> predecessors(boost::num_vertices(g));
std::vector<Weight> distances(boost::num_vertices(g));
IndexMap indexMap = boost::get(boost::vertex_index, g);
PredecessorMap predecessorMap(&predecessors[0], indexMap);
DistanceMap distanceMap(&distances[0], indexMap);
boost::dijkstra_shortest_paths(g, vertex_map[start_vertex],
boost::distance_map(distanceMap)
.predecessor_map(predecessorMap));
NameMap nameMap = boost::get(boost::vertex_name, g);
std::cout << std::endl;
typedef std::vector<Graph::edge_descriptor> PathType;
PathType path;
Vertex v = vertex_map[end_vertex];
for(Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
std::pair<Graph::edge_descriptor, bool> edgePair = boost::edge(u, v, g);
Graph::edge_descriptor edge = edgePair.first;
path.push_back(edge);
}
std::cout << "Shortest path from " << start_vertex << " to " << end_vertex
<< std::endl;
for(PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator
!= path.rend(); ++pathIterator) {
std::cout << nameMap[boost::source(*pathIterator, g)] << " -> "
<< nameMap[boost::target(*pathIterator, g)]
<< " = " << boost::get(boost::edge_weight, g, *pathIterator)
<< std::endl;
}
std::cout << std::endl;
std::cout << "Distance: " << distanceMap[vertex_map[end_vertex]] << std::endl;
std::cout << std::end;
return EXIT_SUCCESS;
}
输入文件示例:
Vertices:
S,H,R,C,G
Edges
(S,C,39)
(R,S,86)
(G,S,74)
(C,H,55)
(R,C,126)
(G,C,68)
(R,H,111)
(G,R,56)
(H,G,97)
(S,H,27)
最佳答案
Graph g(sizeof(_vertices));
那是一个错误.你想写.
Graph g(_vertices.size());
但是,这仍然是错误的.您已经在循环中添加顶点(add_vertex),因此您无需预先填充图形.
Graph g;
工作演示
下面的程序有一些样式修复(允许我读取代码,以及依赖于解析更多),我用所有可能的有效输入进行了详尽的测试:
for i in {S,H,R,C,G}\ {S,H,R,C,G}; do valgrind ./test <<< $i; done
(与http://paste.ubuntu.com/14002530/相同)
它显示所有运行完全干净,没有可检测到的内存错误.
#include <boost/algorithm/string.hpp>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <boost/graph/properties.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace {
typedef int Weight;
typedef boost::property<boost::vertex_name_t, std::string> VertexNameProperty;
typedef boost::property<boost::edge_weight_t, Weight> EdgeWeightProperty;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, VertexNameProperty, EdgeWeightProperty> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
typedef boost::property_map<Graph, boost::vertex_name_t>::type NameMap;
typedef boost::iterator_property_map<Vertex*, IndexMap, Vertex, Vertex&> PredecessorMap;
typedef boost::iterator_property_map<Weight*, IndexMap, Weight, Weight&> DistanceMap;
}
template <typename V, typename VM>
Graph readGraph(std::string const& fname, V& _vertices, VM& vertex_map) {
std::ifstream input(fname);
std::string line, vertex;
std::getline(input, line);
assert(line == "Vertices:");
std::getline(input, line);
boost::char_separator<char> sep(",");
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
tokenizer tok(line, sep);
for (auto &i : tok) {
_vertices.insert(_vertices.end(), i);
}
Graph g;
for (auto &i : _vertices) {
vertex_map[i] = boost::add_vertex(std::string(i), g);
}
char c;
struct GraphParameters {
char source, target;
Weight weight;
};
std::getline(input, line);
assert(line == "Edges");
while (getline(input, line)) {
GraphParameters p;
std::istringstream iss(line);
if (iss >> c && c == '('
&& iss >> p.source >> c && c == ','
&& iss >> p.target >> c && c == ','
&& iss >> p.weight >> c && c == ')')
{
boost::add_edge(
vertex_map[std::string(1,p.source)],
vertex_map[std::string(1,p.target)],
p.weight,
g);
} else {
throw std::runtime_error("Parse error in '" + line + "'\n");
}
}
return g;
}
int main() {
std::vector<std::string> _vertices;
std::map<std::string, Vertex> vertex_map;
auto g = readGraph("input.txt", _vertices, vertex_map);
std::string start_vertex, end_vertex;
bool valid = false;
std::cout << "Vertices:" << std::endl;
for (auto &i : _vertices) {
std::cout << i << " ";
}
std::cout << std::endl;
while (!valid) {
std::cout << "Enter starting vertex: ";
std::cin >> start_vertex;
for (auto &i : _vertices) {
if (i == start_vertex) {
valid = true;
break;
}
}
}
while (valid) {
std::cout << "Enter ending vertex: ";
std::cin >> end_vertex;
for (auto &i : _vertices) {
if (i == end_vertex) {
valid = false;
break;
}
}
}
std::vector<Vertex> predecessors(boost::num_vertices(g));
std::vector<Weight> distances(boost::num_vertices(g));
IndexMap indexMap = boost::get(boost::vertex_index, g);
PredecessorMap predecessorMap(&predecessors[0], indexMap);
DistanceMap distanceMap(&distances[0], indexMap);
boost::dijkstra_shortest_paths(g, vertex_map[start_vertex],
boost::distance_map(distanceMap).predecessor_map(predecessorMap));
NameMap nameMap = boost::get(boost::vertex_name, g);
std::cout << std::endl;
typedef std::vector<Graph::edge_descriptor> PathType;
PathType path;
Vertex v = vertex_map[end_vertex];
for (Vertex u = predecessorMap[v]; u != v; v = u, u = predecessorMap[v]) {
std::pair<Graph::edge_descriptor, bool> edgePair = boost::edge(u, v, g);
Graph::edge_descriptor edge = edgePair.first;
path.push_back(edge);
}
std::cout << "Shortest path from " << start_vertex << " to " << end_vertex << std::endl;
for (PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator) {
std::cout << nameMap[boost::source(*pathIterator, g)] << " -> " << nameMap[boost::target(*pathIterator, g)]
<< " = " << boost::get(boost::edge_weight, g, *pathIterator) << std::endl;
}
std::cout << std::endl;
std::cout << "Distance: " << distanceMap[vertex_map[end_vertex]] << std::endl;
std::cout << std::endl;
return EXIT_SUCCESS;
}