如何将GraphML中的边权重导入至boost::dijkstra_shortest_paths并解决bad_any_cast异常问题
解决Boost GraphML读取与Dijkstra算法的问题
我来帮你梳理下代码里的问题,一步步修正让它正常运行:
核心问题分析
你的代码主要有三个关键问题:
- 图类型未定义边权重属性:你用的
adjacency_list没有预留存储边权重的位置,导致读取的权重无法关联到图的边。 - 属性绑定错误:GraphML里的边权重属性名称是
weight(对应<key>的attr.name),但你绑定了d1(这是key的id,不是属性名称),所以无法正确映射权重值。 - Dijkstra参数配置错误:你把边权重映射传给了
distance_map参数,而distance_map是用来存储顶点到源点的距离的,边权重应该用weight_map参数传入。
修改后的完整代码
#include <boost/graph/adjacency_list.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> #include <boost/graph/graphml.hpp> #include <boost/property_map/property_map.hpp> #include <iostream> #include <fstream> #include <vector> #include <map> using namespace std; // 定义带有边权重属性的图类型 using EdgeProperty = boost::property<boost::edge_weight_t, double>; using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, EdgeProperty>; using Vertex = boost::graph_traits<Graph>::vertex_descriptor; using Edge = boost::graph_traits<Graph>::edge_descriptor; using IndexMap = boost::property_map<Graph, boost::vertex_index_t>::type; using EdgeWeightMap = boost::property_map<Graph, boost::edge_weight_t>::type; int main(int argc, char *argv[]) { if (argc <= 1) { cout << "No GraphML file given." << endl; return 1; } Graph g; boost::dynamic_properties dp{boost::ignore_other_properties}; // 绑定GraphML中的"weight"属性到图的edge_weight_t属性 EdgeWeightMap edge_weight_map = get(boost::edge_weight, g); dp.property("weight", edge_weight_map); // 读取GraphML文件 ifstream in{argv[1]}; if (!in.is_open()) { cout << "Failed to open file: " << argv[1] << endl; return 1; } boost::read_graphml(in, g, dp); // -------------------------- // 调试输出:验证边权重是否正确读取 // -------------------------- cout << "Edge weights read from GraphML:" << endl; auto edges = boost::edges(g); for (auto e_it = edges.first; e_it != edges.second; ++e_it) { Edge e = *e_it; Vertex u = boost::source(e, g); Vertex v = boost::target(e, g); double weight = get(edge_weight_map, e); cout << "Edge " << u << " -> " << v << ", weight: " << weight << endl; } // 选择源节点(这里选第一个节点) Vertex source_node = *boost::vertices(g).first; cout << "\nRunning Dijkstra from vertex " << source_node << endl; // 存储每个顶点到源点的距离 vector<double> distances(num_vertices(g)); auto distance_map = boost::make_iterator_property_map( distances.begin(), get(boost::vertex_index, g)); // 运行Dijkstra最短路径算法 boost::dijkstra_shortest_paths( g, source_node, boost::distance_map(distance_map) .weight_map(edge_weight_map)); // 输出结果 cout << "Shortest distances from source:" << endl; auto vertices = boost::vertices(g); for (auto v_it = vertices.first; v_it != vertices.second; ++v_it) { Vertex v = *v_it; cout << "Vertex " << v << ": " << distances[v] << endl; } return 0; }
关键修改说明
1. 图类型定义
我修改了adjacency_list的模板参数,添加了EdgeProperty作为边属性类型,这样图的每条边都能存储double类型的权重值:
using EdgeProperty = boost::property<boost::edge_weight_t, double>; using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, boost::no_property, EdgeProperty>;
2. 正确绑定GraphML属性
GraphML中<key id="d1" for="edge" attr.name="weight">的attr.name是weight,这才是属性的逻辑名称,所以我们要绑定"weight"到图的edge_weight_t属性:
EdgeWeightMap edge_weight_map = get(boost::edge_weight, g); dp.property("weight", edge_weight_map);
3. 正确配置Dijkstra参数
distance_map:传入存储顶点距离的映射(这里用vector<double>包装的迭代器属性映射)weight_map:传入边权重的映射,告诉Dijkstra算法用这个值作为边的权重
调试方法
代码里添加了遍历所有边并输出权重的代码,你可以通过这个验证GraphML里的权重是否被正确读取。另外,如果你想检查dynamic_properties里的内容,可以尝试遍历它的属性,但更简单的方式是直接验证图的边属性,因为我们已经把属性绑定到了图的内置映射里。
处理GraphML中的默认权重
注意你提供的GraphML里,<edge id="e1">没有指定weight值,Boost会自动用double的默认值0.0填充这条边的权重,如果需要自定义默认值,可以在定义EdgeProperty时指定:
using EdgeProperty = boost::property<boost::edge_weight_t, double, 1.0>; // 默认权重1.0
内容的提问来源于stack exchange,提问作者Anaphory
相关产品推荐
相关产品推荐

