半生不熟的快速概念验证
您可以在以adjacency_list 定义的图形上使用add_edge() 和remove_vertex()
#include <iostream>
#include <iterator>
#include <boost/graph/adjacency_list.hpp>
using V = unsigned;
using E = std::pair<V, V>;
using G = boost::adjacency_list<boost::vecS, boost::vecS>;
void print_graph(G const& g)
{
auto vs = boost::vertices(g);
for (auto vit = vs.first; vit != vs.second; ++vit) {
auto neighbors = boost::adjacent_vertices(*vit, g);
for (auto nit = neighbors.first; nit != neighbors.second; ++nit)
std::cout << "{" << *vit << "," << *nit << "}" << ", ";
}
std::cout << "\n";
}
void contract_vertices(V b, V a, G& g)
{
auto be = boost::adjacent_vertices(b, g);
for (auto beit = be.first; beit != be.second; ++beit)
add_edge(a, *beit, g);
remove_vertex(b, g);
}
int main()
{
// named vertices
auto const A = V { 1 };
auto const B = V { 2 };
// construct the graph
auto e = std::vector<E> { { A, 3 }, { B, 4 } };
auto g = G { std::begin(e), std::end(e), 4 };
print_graph(g);
contract_vertices(B, A, g);
print_graph(g);
}
Live example 打印
{1,3}, {2,4},
{1,2}、{1,3}、
输出并不完全符合您的预期,因为顶点的标签也被更新以反映 B 的删除,这导致节点 3 和 4 现在被标记为 2 和 3。
库质量代码的要求
用于收缩顶点 u 和 v 的通用库质量算法通常应至少考虑以下极端情况
- 移除 (u,v) 和 (v,u) 边;
- 将所有 u 和 v 外边缘与共同目标合并;
- 将所有 u 和 v 入边与公共源合并;
- 将其余的 u 外边缘移至 v;
- 将剩余的 u 内边移到 v;
Boost.Graph 为此类操作提供了所有必需的原语:in_edges()、out_edges()、add_edge()、clear_vertex()、remove_vertex()。对于无向图,其中几个项目可以在一个步骤中完成,而对于有向图,通常需要两个步骤。
除了这些算法步骤之外,还应该定义合并或移动边缘的语义。例如。他们的财产应该怎么办?这类似于例如合并两家公司:合资公司应以哪个名称运营?
为什么 Boost.Graph 没有(还)提供contract_vertices()
TL;DR我不知道。但我可以推测。主要是应该指定一个假定的contract_vertices() 的接口。除了要收缩的两个顶点以及它们所属的图类型之外,还应该定义边缘属性的合并和移动操作。理论上,应该可以使用适合通用算法的模板参数来做到这一点。