BOOS库中Graph模块boost::edge_reverse_t和boost::vertex_color_t解读

boost::edge_reverse_t

一、boost::edge_reverse_t 是什么

1 定义

boost::edge_reverse_t 是一个 Edge Property Tag,用于标记一条边的"反向边(reverse edge)"。

重点:

  • 它本身不存储数据
  • 只是一个类型标签
  • 用于 property_map 绑定 edge_descriptor

1.2 数学语义(最大流背景)

对于一条边 ( e=(u→v)e = (u \to v)e=(u→v) ):

  • 反向边 ( erev=(v→u)e^{rev} = (v \to u)erev=(v→u) )
  • 残量更新公式:

r(e)=c(e)−f(e),r(erev)=f(e) r(e) = c(e) - f(e), \quad r(e^{rev}) = f(e) r(e)=c(e)−f(e),r(erev)=f(e)

算法必须能通过 edge_reverse 找到反向边


二、edge_reverse_t 在 Boost.Graph 类型系统中的角色

cpp 复制代码
struct edge_reverse_t {};
  • 属于 property tag
  • 内置成员类型:kind = edge_property_tag
  • 作为 编译期契约让算法可以安全访问 reverse edge

2.1 与 edge_capacity_t 对比

属性 含义 是否变化 作用
edge_capacity_t 边容量上限 流网络限制
edge_residual_capacity_t 残量 算法动态更新
edge_reverse_t 反向边指针 找到反向边进行回退

三、edge_reverse_t 的数据实现方式

3.1 在 adjacency_list 中的实现

cpp 复制代码
struct stored_edge {
    VertexDescriptor target;
    EdgeProperty property; // 可能嵌套 edge_reverse_t
};

然后 property_map:

cpp 复制代码
boost::property_map<Graph, edge_reverse_t>::type reverse_edges = get(edge_reverse, g);

访问方式:

cpp 复制代码
EdgeDesc rev = reverse_edges[e];
  • e:当前边的 edge_descriptor
  • rev:反向边的 edge_descriptor

算法通过 rev 可以直接访问对端边(残量流更新)


3.2 为什么 adjacency_list 需要 edge_reverse

在 adjacency_list 中:

  • edge_descriptor = (source, index)
  • 无法自动知道反向边(target -> source
  • 必须显式存储反向边 descriptor
text 复制代码
EdgeList: out_edges[source] = [...]
EdgeList: out_edges[target] = [...]

四、算法如何使用 edge_reverse

4.1 Dinic / Edmonds-Karp / Push-Relabel

  1. 构建正向边 (e)
  2. 构建反向边 (e^{rev})
  3. edge_reverse[e] = e^{rev}edge_reverse[e^{rev}] = e
  4. 算法核心循环:
cpp 复制代码
residual[e] -= delta;
residual[reverse_edges[e]] += delta;
  • 正向减少流
  • 反向增加流(回退)

4.2 代码示例

cpp 复制代码
auto e1 = add_edge(u, v, g).first;
auto e2 = add_edge(v, u, g).first;

capacity[e1] = cap;
capacity[e2] = 0;

reverse_edges[e1] = e2;
reverse_edges[e2] = e1;

注意:反向边容量一般为 0(初始残量网络)


五、edge_reverse_t 的核心价值

  1. 零开销的泛型抽象

    • 算法不关心边存在哪个容器
    • 只通过 reverse_edges[e] 找到反向边
  2. 统一算法接口

    • Dinic / Push-Relabel / Max-Flow 都使用同一个接口
  3. 内存布局解耦

    • 反向边 descriptor 可以存任何类型(pair / struct / index)

六、工程实践

6.1 自定义 Graph 下的实现方式

如果你有自己的 Graph:

cpp 复制代码
struct Edge {
    uint32_t dst;
    uint32_t reverse_id; // 对应 reverse edge 索引
    double capacity;
};

更新残量流:

cpp 复制代码
auto &e  = g.adj[u][i];
auto &er = g.adj[e.dst][e.reverse_id];

e.capacity -= delta;
er.capacity += delta;

完全内建 reverse,无需 property_map


6.2 常见误区

没有建立反向边

正向 / 反向容量设置错误

reverse_edges 和 residual_edges 类型不匹配

忘记双向绑定


七、源码追踪

  1. Tag 定义
text 复制代码
boost/graph/properties.hpp
struct edge_reverse_t { typedef edge_property_tag kind; };
BOOST_INSTALL_PROPERTY(edge, reverse);
  1. property_map
text 复制代码
boost/graph/detail/adjacency_list.hpp
get(edge_reverse, g) → adjacency_list_edge_property_map
  1. 算法层面
  • Dinic / push_relabel / edmonds_karp
  • 使用 property_map 访问 reverse edge

八、与 SLAM / 因子图的类比

Flow Graph SLAM Graph
edge_capacity_t 约束权重上限
edge_reverse_t 约束残差回传方向
residual_capacity_t 可调节自由度

本质都是"正向约束 + 回退"


九、 总结

  • boost::edge_reverse_t 是边的反向标识 tag
  • 它是算法与图结构之间的编译期契约
  • 实际数据存储在 property_map 中
  • 在最大流算法中,核心作用是找到反向边进行流回退
  • 工程实践中,你可以自定义 Graph 内建 reverse_id,实现零开销访问

boost::vertex_color_t

一、boost::vertex_color_t 是什么?

1 定义

boost::vertex_color_t 是一个 Vertex Property Tag,用于标记顶点的访问状态(颜色)。

重点:

  • 它本身不存储数据
  • 只是一个类型标签
  • 与 BFS、DFS、拓扑排序等遍历算法强绑定

1.2 数学语义

在图遍历中,通常把顶点标记为三种颜色:

颜色 含义
white 未访问(初始状态)
gray 已发现但未完成探索
black 已完成探索

对应 BFS/DFS 算法中的状态标记。


二、vertex_color_t 在 Boost.Graph 类型系统中的角色

cpp 复制代码
struct vertex_color_t {};
  • 属于 property tag
  • 内置成员类型:kind = vertex_property_tag
  • 作为 编译期契约让算法可以安全访问顶点颜色

2.1 与 vertex_index_t 对比

属性 含义 是否变化 作用
vertex_index_t 顶点编号 vertex_descriptor → 索引
vertex_color_t 顶点颜色 遍历状态标记

三、vertex_color_t 的数据实现方式

3.1 在 adjacency_list 中的定义

cpp 复制代码
using Graph = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::directedS,
    boost::property<boost::vertex_color_t, boost::default_color_type>
>;
含义
  • 每个顶点都会有一个颜色字段
  • 类型一般为 boost::default_color_type(枚举:white/gray/black)

3.2 property_map

获取颜色 map:

cpp 复制代码
auto color = get(boost::vertex_color, g);

使用方式:

cpp 复制代码
color[u] = boost::gray_color;
if(color[v] == boost::white_color) ...

注意:color_map 是对顶点数组的 直接访问器,零开销。


四、算法使用 vertex_color_t

4.1 BFS

cpp 复制代码
boost::breadth_first_search(g, s,
    boost::visitor(visitor)
        .color_map(color)
);
  • 初始状态所有顶点 white
  • 发现顶点标记 gray
  • 完成访问标记 black

4.2 DFS

cpp 复制代码
boost::depth_first_search(g,
    boost::visitor(visitor)
        .color_map(color)
);
  • DFS 依赖颜色判断是否回退
  • 避免重复访问

4.3 拓扑排序 / 强连通分量

  • 颜色 map 用于标记访问状态
  • 避免重复处理顶点

五、vertex_color_t 的核心价值

  1. 算法与图分离

    • 算法不关心颜色字段存储在哪
    • 通过 property_map 获取
  2. 零开销泛型抽象

    • 可以替换为 external color map
    • 遍历算法依旧正常
  3. 允许外部复用

    • 例如同一个颜色 map 用于 BFS/DFS/拓扑排序

六、external color map

cpp 复制代码
std::vector<boost::default_color_type> color_storage(num_vertices(g));
auto color = boost::make_iterator_property_map(color_storage.begin(), get(boost::vertex_index, g));
  • 不在图内部存储颜色
  • 支持共享或多次遍历

七、源码追踪

  1. Tag 定义
cpp 复制代码
boost/graph/properties.hpp
struct vertex_color_t { typedef vertex_property_tag kind; };
BOOST_INSTALL_PROPERTY(vertex, color);
  1. property_map 特化
cpp 复制代码
boost/graph/detail/adjacency_list.hpp
get(vertex_color, g) -> adjacency_list_vertex_property_map
  1. 算法层面
  • BFS / DFS / Topological / Strong components
  • 都通过 get(color_tag, g) 获取颜色 map

八、工程实践

8.1 自定义 Graph 下的实现

cpp 复制代码
struct Vertex {
    boost::default_color_type color;
};

std::vector<Vertex> vertices;
auto color = make_iterator_property_map(vertices.begin(), get(vertex_index, g), &Vertex::color);
  • 同样可以被 BFS/DFS 使用
  • 支持外部复用
  • 支持零开销访问

8.2 常见误区

忘记初始化颜色 → 遍历结果不正确

同时用多个遍历共用同一个 color map(未清零)

使用非标准类型(算法只支持 default_color_type 枚举)


九、与 SLAM / 优化的类比

Boost.Graph SLAM / 因子图
vertex_color_t 顶点状态标记(已处理 / 待处理 / 在队列中)
white_color 未优化 / 未处理
gray_color 当前队列 / 正在优化
black_color 优化完成 / 固定

可以理解为BFS/DFS的访问状态 ≈ SLAM图节点的处理状态


十、 总结

  • boost::vertex_color_t 是顶点颜色的类型标签
  • 遍历算法的核心依赖
  • 通过 property_map 与图解耦
  • 可以在内部或外部实现,支持零开销泛型算法
  • 工程实践中,必须初始化并正确管理状态

相关推荐
尽兴-2 小时前
《深入剖析:全面理解 MySQL 的架构设计》
数据库·mysql·数据库架构设计·理解mysql架构
在风中的意志2 小时前
[数据库SQL] [leetcode] 2388. 将表中的空值更改为前一个值
数据库·sql·leetcode
梦幻通灵2 小时前
Mysql字段判空实用技巧
android·数据库·mysql
酸菜牛肉汤面4 小时前
23、varchar与char的区别
数据库
AI题库4 小时前
PostgreSQL 18 从新手到大师:实战指南 - 2.5 Serverless PostgreSQL
数据库·postgresql·serverless
IT技术分享社区4 小时前
数据库实战:MySQL多表更新JOIN操作的底层原理与性能调优指南
数据库·mysql·程序员
廋到被风吹走4 小时前
【数据库】【Oracle】分区表与大表设计
数据库·oracle
UrSpecial5 小时前
InnoDB存储引擎
数据库·mysql
gjc5925 小时前
MySQL隐蔽 BUG:组合条件查询无故返回空集?深度排查与规避方案
android·数据库·mysql·bug