如何可视化boost图并执行dijkstra的最短路径?
How to visualize the boost graph and perform dijkstra's shortest path?
我正在尝试用 Dijkstra 的最短路径制作图表。顶点大小稍后可能会有所不同,所以我决定制作一堆循环来创建边。我正在努力可视化点文件中的图形。
我试过了
std::ofstream dot_file("grid.dot"); boost::write_graphviz(dot_file, g);
但这不会生成任何新的网格文件并且不会出错。
此外,我正在尝试应用 Dijkstra 的最短路径函数。但是这一行给我一个错误。
dijkstra_shortest_paths(g, vtx_distance, predecessor_map(&p[0]).distance_map(&d[0]));
#include <stdint.h>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
using namespace std;
using namespace boost;
int main() {
struct Vertex {int index;};
struct Edge {int weight;};
typedef adjacency_list<vecS, vecS, bidirectionalS, Vertex, Edge> Graph;
Graph g;
typedef graph_traits < Graph >::vertex_descriptor vertex_t;
typedef graph_traits < Graph >::edge_descriptor edge_t;
typedef graph_traits <Graph> Traits;
vector<int> vertices;
int size = 9;
int size_x = 3;
int size_y = 3;
for (int i = 0; i < size; i++){
vertices.push_back(i);
}
vector<vertex_t> vtx;
for (int i = 0; i<vertices.size(); i++) {
vertex_t tmp = add_vertex(g);
g[tmp].index = vertices.at(i);
vtx.push_back(tmp);
}
//Add edge in horizontal
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] % size_x !=2){
add_edge(vtx[i], vtx[i + 1], g);
}
}
//Add edge in vertical
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] < size - size_y){
add_edge(vtx[i], vtx[i + size_x], g);
}
}
//Add edge in diagonal 1
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] % size_x != 2 && vertices[i] < size - size_y){
add_edge(vtx[i], vtx[i + 1 + size_x], g);
}
}
//Add edge in diagonal 2
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] % size_x != 0 && vertices[i] < size - size_y){
add_edge(vtx[i], vtx[i - 1 + size_x], g);
}
}
vector<int> d(num_vertices(g));
vector<vertex_t> p(num_vertices(g));
vertex_t vtx_distance = vertex(0, g);
dijkstra_shortest_paths(g, vtx_distance, predecessor_map(&p[0]).distance_map(&d[0]));
std::cout << "distances and parents:" << std::endl;
// std::ofstream file("grid.dot");
std::ofstream dot_file("grid.dot");
boost::write_graphviz(dot_file, g);
}
我要制作的图表的图像(没有 dijkstra)。
作为第一步,我检查了您的图表创建代码。这似乎不必要地复杂。
进入网格
让我们简化一下,基于观察 vecS
顶点容器选择器意味着连续的整数顶点描述符,从 0 开始:
Graph make_grid(size_t size_x, int size_y)
{
Graph g(size_x * size_y);
using boost::make_iterator_range;
for (auto v : boost::make_iterator_range(vertices(g)))
g[v].index = v;
auto col = [=](vertex_t v) { return v % size_x; };
auto row = [=](vertex_t v) { return v / size_x; };
auto lastcol = [=](vertex_t v) { return col(v) == size_x - 1; };
auto lastrow = [=](vertex_t v) { return row(v) == size_y - 1; };
// Add edges
for (auto v : boost::make_iterator_range(vertices(g))) {
if (not lastrow(v))
add_edge(v, v + size_x, g); // vertical
if (not lastcol(v))
add_edge(v, v + 1, g); // horizontal
if (not(lastrow(v) || lastcol(v)))
add_edge(v, v + 1 + size_x, g); // down-right
if (not(lastrow(v) || 0 == col(v)))
add_edge(v, v - 1 + size_x, g); // down-left
}
return g;
}
就是这样。它制作了图表。
发布它!
现在您要打印它。让我们这样做:
std::ofstream dot_file("grid.dot");
boost::write_graphviz(dot_file, g);
if (auto code = system("neato -T png grid.dot -o grid.png"))
return code;
结果
编辑有话要说
您可以使用 graphviz node/edge 属性来增添趣味。让我们添加颜色并保存它们:
struct Edge { int weight; std::string color; };
...
// generating different color edges per direction
if (not lastrow(v))
add_edge(v, v + size_x, Edge{weightgen(), "red"}, g); // vertical
if (not lastcol(v))
add_edge(v, v + 1, Edge{weightgen(), "green"}, g); // horizontal
if (not(lastrow(v) || lastcol(v)))
add_edge(v, v + 1 + size_x, Edge{weightgen(), "blue"}, g); // down-right
if (not(lastrow(v) || 0 == col(v)))
add_edge(v, v - 1 + size_x, Edge{weightgen(), "brown"}, g); // down-left
让我们也将保存提取到一个函数中:
void save(std::string const name, Graph const& g) {
std::ofstream dot_file(name + ".dot");
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("label", get(&Edge::weight, g));
dp.property("color", get(&Edge::color, g));
dp.property("fontcolor", get(&Edge::color, g));
boost::write_graphviz_dp(dot_file, g, dp);
std::ostringstream cmd;
cmd << "neato -T png " //
<< std::quoted(name + ".dot", '\'') << " -o "
<< std::quoted(name + ".png", '\'');
if (auto code = system(cmd.str().c_str())) {
if (code == -1)
::perror(name.data());
::exit(code);
}
}
现在的结果是:
请输入 Dijkstra
你有编译失败。它们是由于使用原始指针(&d[0]
例如)作为 属性 映射。这在很久以前就已被弃用和删除。因此,改为制作显式 属性 映射,例如:
auto vidx = get(boost::vertex_index, g);
auto wmap = get(&Edge::weight, g);
auto dmap = boost::make_iterator_property_map(d.begin(), vidx);
auto pmap = boost::make_iterator_property_map(p.begin(), vidx);
dijkstra_shortest_paths( //
g, //
V{0}, //
boost::predecessor_map(pmap) //
.distance_map(dmap) //
.weight_map(wmap));
即编译。我不太确定您想要可视化的输出到底是什么。或许我们可以将不在路径中的任何边缘变灰?
for (auto e : make_iterator_range(edges(g))) {
auto v = source(e,g), u = target(e,g);
if (p.at(u) != v)
g[e].color = "lightgrey";
}
结果是:
完整列表
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graphviz.hpp>
#include <iostream>
struct Vertex { int index; };
struct Edge { int weight; std::string color; };
using Graph = boost::adjacency_list< //
boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge>;
using Traits = boost::graph_traits<Graph>;
using V = Traits::vertex_descriptor;
using E = Traits::edge_descriptor;
Graph make_grid(size_t size_x, size_t size_y)
{
Graph g(size_x * size_y);
using boost::make_iterator_range;
for (auto v : boost::make_iterator_range(vertices(g)))
g[v].index = v;
auto col = [=](V v) { return v % size_x; };
auto row = [=](V v) { return v / size_x; };
auto lastcol = [=](V v) { return col(v) == size_x - 1; };
auto lastrow = [=](V v) { return row(v) == size_y - 1; };
// Add edges
auto weightgen = [] { return rand() % 5 + 1; };
for (auto v : boost::make_iterator_range(vertices(g))) {
if (not lastrow(v))
add_edge(v, v + size_x, Edge{weightgen(), "red"}, g); // vertical
if (not lastcol(v))
add_edge(v, v + 1, Edge{weightgen(), "green"}, g); // horizontal
if (not(lastrow(v) || lastcol(v)))
add_edge(v, v + 1 + size_x, Edge{weightgen(), "blue"}, g); // down-right
if (not(lastrow(v) || 0 == col(v)))
add_edge(v, v - 1 + size_x, Edge{weightgen(), "brown"}, g); // down-left
}
return g;
}
void save(std::string const name, Graph& g) {
std::ofstream dot_file(name + ".dot");
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("label", get(&Edge::weight, g));
dp.property("color", get(&Edge::color, g));
dp.property("fontcolor", get(&Edge::color, g));
boost::write_graphviz_dp(dot_file, g, dp);
std::ostringstream cmd;
cmd << "neato -T png " //
<< std::quoted(name + ".dot", '\'') << " -o "
<< std::quoted(name + ".png", '\'');
if (auto code = system(cmd.str().c_str())) {
if (code == -1)
::perror(name.data());
::exit(code);
}
}
int main() {
Graph g = make_grid(3, 3);
save("grid", g);
std::vector<int> d(num_vertices(g));
std::vector<V> p(num_vertices(g));
auto vidx = get(boost::vertex_index, g);
auto wmap = get(&Edge::weight, g);
auto dmap = boost::make_iterator_property_map(d.begin(), vidx);
auto pmap = boost::make_iterator_property_map(p.begin(), vidx);
dijkstra_shortest_paths( //
g, //
V{0}, //
boost::predecessor_map(pmap) //
.distance_map(dmap) //
.weight_map(wmap));
for (auto e : make_iterator_range(edges(g))) {
auto v = source(e,g), u = target(e,g);
if (p.at(u) != v)
g[e].color = "lightgrey";
}
save("path", g);
}
我正在尝试用 Dijkstra 的最短路径制作图表。顶点大小稍后可能会有所不同,所以我决定制作一堆循环来创建边。我正在努力可视化点文件中的图形。
我试过了
std::ofstream dot_file("grid.dot"); boost::write_graphviz(dot_file, g);
但这不会生成任何新的网格文件并且不会出错。
此外,我正在尝试应用 Dijkstra 的最短路径函数。但是这一行给我一个错误。
dijkstra_shortest_paths(g, vtx_distance, predecessor_map(&p[0]).distance_map(&d[0]));
#include <stdint.h>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
using namespace std;
using namespace boost;
int main() {
struct Vertex {int index;};
struct Edge {int weight;};
typedef adjacency_list<vecS, vecS, bidirectionalS, Vertex, Edge> Graph;
Graph g;
typedef graph_traits < Graph >::vertex_descriptor vertex_t;
typedef graph_traits < Graph >::edge_descriptor edge_t;
typedef graph_traits <Graph> Traits;
vector<int> vertices;
int size = 9;
int size_x = 3;
int size_y = 3;
for (int i = 0; i < size; i++){
vertices.push_back(i);
}
vector<vertex_t> vtx;
for (int i = 0; i<vertices.size(); i++) {
vertex_t tmp = add_vertex(g);
g[tmp].index = vertices.at(i);
vtx.push_back(tmp);
}
//Add edge in horizontal
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] % size_x !=2){
add_edge(vtx[i], vtx[i + 1], g);
}
}
//Add edge in vertical
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] < size - size_y){
add_edge(vtx[i], vtx[i + size_x], g);
}
}
//Add edge in diagonal 1
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] % size_x != 2 && vertices[i] < size - size_y){
add_edge(vtx[i], vtx[i + 1 + size_x], g);
}
}
//Add edge in diagonal 2
for (int i = 0; i<vertices.size(); i++){
if (vertices[i] % size_x != 0 && vertices[i] < size - size_y){
add_edge(vtx[i], vtx[i - 1 + size_x], g);
}
}
vector<int> d(num_vertices(g));
vector<vertex_t> p(num_vertices(g));
vertex_t vtx_distance = vertex(0, g);
dijkstra_shortest_paths(g, vtx_distance, predecessor_map(&p[0]).distance_map(&d[0]));
std::cout << "distances and parents:" << std::endl;
// std::ofstream file("grid.dot");
std::ofstream dot_file("grid.dot");
boost::write_graphviz(dot_file, g);
}
我要制作的图表的图像(没有 dijkstra)。
作为第一步,我检查了您的图表创建代码。这似乎不必要地复杂。
进入网格
让我们简化一下,基于观察 vecS
顶点容器选择器意味着连续的整数顶点描述符,从 0 开始:
Graph make_grid(size_t size_x, int size_y)
{
Graph g(size_x * size_y);
using boost::make_iterator_range;
for (auto v : boost::make_iterator_range(vertices(g)))
g[v].index = v;
auto col = [=](vertex_t v) { return v % size_x; };
auto row = [=](vertex_t v) { return v / size_x; };
auto lastcol = [=](vertex_t v) { return col(v) == size_x - 1; };
auto lastrow = [=](vertex_t v) { return row(v) == size_y - 1; };
// Add edges
for (auto v : boost::make_iterator_range(vertices(g))) {
if (not lastrow(v))
add_edge(v, v + size_x, g); // vertical
if (not lastcol(v))
add_edge(v, v + 1, g); // horizontal
if (not(lastrow(v) || lastcol(v)))
add_edge(v, v + 1 + size_x, g); // down-right
if (not(lastrow(v) || 0 == col(v)))
add_edge(v, v - 1 + size_x, g); // down-left
}
return g;
}
就是这样。它制作了图表。
发布它!
现在您要打印它。让我们这样做:
std::ofstream dot_file("grid.dot");
boost::write_graphviz(dot_file, g);
if (auto code = system("neato -T png grid.dot -o grid.png"))
return code;
结果
编辑有话要说
您可以使用 graphviz node/edge 属性来增添趣味。让我们添加颜色并保存它们:
struct Edge { int weight; std::string color; };
...
// generating different color edges per direction
if (not lastrow(v))
add_edge(v, v + size_x, Edge{weightgen(), "red"}, g); // vertical
if (not lastcol(v))
add_edge(v, v + 1, Edge{weightgen(), "green"}, g); // horizontal
if (not(lastrow(v) || lastcol(v)))
add_edge(v, v + 1 + size_x, Edge{weightgen(), "blue"}, g); // down-right
if (not(lastrow(v) || 0 == col(v)))
add_edge(v, v - 1 + size_x, Edge{weightgen(), "brown"}, g); // down-left
让我们也将保存提取到一个函数中:
void save(std::string const name, Graph const& g) {
std::ofstream dot_file(name + ".dot");
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("label", get(&Edge::weight, g));
dp.property("color", get(&Edge::color, g));
dp.property("fontcolor", get(&Edge::color, g));
boost::write_graphviz_dp(dot_file, g, dp);
std::ostringstream cmd;
cmd << "neato -T png " //
<< std::quoted(name + ".dot", '\'') << " -o "
<< std::quoted(name + ".png", '\'');
if (auto code = system(cmd.str().c_str())) {
if (code == -1)
::perror(name.data());
::exit(code);
}
}
现在的结果是:
请输入 Dijkstra
你有编译失败。它们是由于使用原始指针(&d[0]
例如)作为 属性 映射。这在很久以前就已被弃用和删除。因此,改为制作显式 属性 映射,例如:
auto vidx = get(boost::vertex_index, g);
auto wmap = get(&Edge::weight, g);
auto dmap = boost::make_iterator_property_map(d.begin(), vidx);
auto pmap = boost::make_iterator_property_map(p.begin(), vidx);
dijkstra_shortest_paths( //
g, //
V{0}, //
boost::predecessor_map(pmap) //
.distance_map(dmap) //
.weight_map(wmap));
即编译。我不太确定您想要可视化的输出到底是什么。或许我们可以将不在路径中的任何边缘变灰?
for (auto e : make_iterator_range(edges(g))) {
auto v = source(e,g), u = target(e,g);
if (p.at(u) != v)
g[e].color = "lightgrey";
}
结果是:
完整列表
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graphviz.hpp>
#include <iostream>
struct Vertex { int index; };
struct Edge { int weight; std::string color; };
using Graph = boost::adjacency_list< //
boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge>;
using Traits = boost::graph_traits<Graph>;
using V = Traits::vertex_descriptor;
using E = Traits::edge_descriptor;
Graph make_grid(size_t size_x, size_t size_y)
{
Graph g(size_x * size_y);
using boost::make_iterator_range;
for (auto v : boost::make_iterator_range(vertices(g)))
g[v].index = v;
auto col = [=](V v) { return v % size_x; };
auto row = [=](V v) { return v / size_x; };
auto lastcol = [=](V v) { return col(v) == size_x - 1; };
auto lastrow = [=](V v) { return row(v) == size_y - 1; };
// Add edges
auto weightgen = [] { return rand() % 5 + 1; };
for (auto v : boost::make_iterator_range(vertices(g))) {
if (not lastrow(v))
add_edge(v, v + size_x, Edge{weightgen(), "red"}, g); // vertical
if (not lastcol(v))
add_edge(v, v + 1, Edge{weightgen(), "green"}, g); // horizontal
if (not(lastrow(v) || lastcol(v)))
add_edge(v, v + 1 + size_x, Edge{weightgen(), "blue"}, g); // down-right
if (not(lastrow(v) || 0 == col(v)))
add_edge(v, v - 1 + size_x, Edge{weightgen(), "brown"}, g); // down-left
}
return g;
}
void save(std::string const name, Graph& g) {
std::ofstream dot_file(name + ".dot");
boost::dynamic_properties dp;
dp.property("node_id", get(boost::vertex_index, g));
dp.property("label", get(&Edge::weight, g));
dp.property("color", get(&Edge::color, g));
dp.property("fontcolor", get(&Edge::color, g));
boost::write_graphviz_dp(dot_file, g, dp);
std::ostringstream cmd;
cmd << "neato -T png " //
<< std::quoted(name + ".dot", '\'') << " -o "
<< std::quoted(name + ".png", '\'');
if (auto code = system(cmd.str().c_str())) {
if (code == -1)
::perror(name.data());
::exit(code);
}
}
int main() {
Graph g = make_grid(3, 3);
save("grid", g);
std::vector<int> d(num_vertices(g));
std::vector<V> p(num_vertices(g));
auto vidx = get(boost::vertex_index, g);
auto wmap = get(&Edge::weight, g);
auto dmap = boost::make_iterator_property_map(d.begin(), vidx);
auto pmap = boost::make_iterator_property_map(p.begin(), vidx);
dijkstra_shortest_paths( //
g, //
V{0}, //
boost::predecessor_map(pmap) //
.distance_map(dmap) //
.weight_map(wmap));
for (auto e : make_iterator_range(edges(g))) {
auto v = source(e,g), u = target(e,g);
if (p.at(u) != v)
g[e].color = "lightgrey";
}
save("path", g);
}