boost笔记:boost::Graph中找出所有环

1. 问题描述

本文描述了找出一个有向连通图中所有的环的解决方案

测试用到的有向连通图

2. 自写算法

通过深度优先遍历算法,发现回边时,即存在环的原理来找出环。对于用共享边的环,以下算法有些环找不出来,如上图中的2->8->9->6->2。为什么找不出来,自己走一边深度优先遍历的过程再结合算法原理即可得知。使用的函数为boost::depth_first_search, 具体参看后文算法实现

3. boost自身实现的tiernan算法找环

使用的函数为boost::tiernan_all_cycles, 具体参看后文算法实现。

注:常规写完后,有编译错误,说找不到标识符renumber_vertex_indices,是个bug, 可参看https://github.com/boostorg/graph/issues/182

4. 完整测试代码与结果

cpp 复制代码
#include <boost/config.hpp>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/tiernan_all_cycles.hpp> 

#include <vector>
#include <map>
#include <stack>

using namespace std;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS> MyGraph;



//只实现了有向图的找环,对于用共享边的环,以下算法有些环找不出来
//boost::add_edge(0, 1, g);
//boost::add_edge(1, 2, g);
//boost::add_edge(2, 3, g);
//boost::add_edge(3, 4, g);
//boost::add_edge(4, 5, g);
//boost::add_edge(4, 2, g);
//boost::add_edge(6, 2, g);
//boost::add_edge(7, 6, g);
//boost::add_edge(4, 7, g);
//boost::add_edge(2, 8, g);
//boost::add_edge(8, 9, g);
//boost::add_edge(9, 6, g);
struct FindCycleVisitor : public boost::default_dfs_visitor
{
	std::stack<MyGraph::vertex_descriptor> m_stack;
	std::vector<MyGraph::vertex_descriptor> m_cycle;

	FindCycleVisitor(){}

	template <class Vertex, class Graph>
	void discover_vertex(Vertex u, const Graph& g)
	{
		m_stack.push(u);
	}

	template <class Edge, class Graph>
	void back_edge(Edge e, const Graph& g) {
		auto u = boost::source(e, g);
		auto v = boost::target(e, g);

		// Find the top of the stack that is an ancestor of v  
		std::stack<MyGraph::vertex_descriptor> temp_stack = m_stack;
		while (!temp_stack.empty() && temp_stack.top() != v) {
			m_cycle.push_back(temp_stack.top());
			temp_stack.pop();
		}
		m_cycle.push_back(v); // Include v in the cycle  

		// Optionally, print or store the cycle  
		std::cout << "Cycle found: ";
		for (auto it = m_cycle.crbegin(); it != m_cycle.crend(); ++it) {
			std::cout << *it << " ";
		}
		std::cout << std::endl;

		// Clear the cycle for the next detection (optional)  
		m_cycle.clear();
	}

	template <class Vertex, class Graph>
	void finish_vertex(Vertex v, const Graph& g) {
		m_stack.pop();
	}
};


// 自定义访问者,用于打印找到的环 
// see https://github.com/boostorg/graph/issues/182
namespace boost
{
	template<typename Graph>
	void renumber_vertex_indices(Graph const&) {}
}
struct TiernanCycleVisitor {
	TiernanCycleVisitor(){}

	template <typename Graph>
	void cycle(const std::vector<typename Graph::vertex_descriptor>& path, Graph g) const
	{
		for (Graph::vertex_descriptor v : path)
		{
			std::cout << v << " ";
		}
		std::cout << std::endl;
	}
};


int main(int argc, char** argv)
{
	MyGraph g;

	boost::add_edge(0, 1, g);
	boost::add_edge(1, 2, g);
	boost::add_edge(2, 3, g);
	boost::add_edge(3, 4, g);
	boost::add_edge(4, 5, g);
	boost::add_edge(4, 2, g);
	boost::add_edge(6, 2, g);
	boost::add_edge(7, 6, g);
	boost::add_edge(4, 7, g);
	boost::add_edge(2, 8, g);
	boost::add_edge(8, 9, g);
	boost::add_edge(9, 6, g);

	//自写算法查找环
	std::cout << "自写算法查找环:" << std::endl;
	FindCycleVisitor vis;
	boost::depth_first_search(g, boost::visitor(vis));

	// 使用tiernan_all_cycles算法查找所有环  
	std::cout << "tiernan算法查找环:" << std::endl;
	TiernanCycleVisitor tiernanVis;
	boost::tiernan_all_cycles(g, tiernanVis);

	return 0;

}
相关推荐
闻缺陷则喜何志丹1 年前
C++算法:图中的最短环
数据结构·c++·算法·图论·bfs·广度有序搜索·