算法--强连通分量

强连通分量

算法性质

本算法执行后
形成的多个分别以某个节点为根的树,同一棵树中节点在G中相互可达
不同棵树中节点p,q无法在G中相互可达。
这样,同一颗树中的节点集合构成了G的一个强连通分量
算法运行后,一次求出了G中所有强连通分量。

接口设计

template<typename Key, typename Value>
class StrongConnectGraph
{
public:
	typename typedef DataStruct::GraphStruct::Graph<Key, Value> InnerGraph;
	StrongConnectGraph(const InnerGraph& nGraph_);
	~StrongConnectGraph();

	DataStruct::Array::DynArray<typename DepthFirstVisit<Key, Value>::Node*> Run();
private:
	StrongConnectGraph(const StrongConnectGraph& nSCG_) = default;
	StrongConnectGraph& operator=(const StrongConnectGraph& nSCG_) = default;
private:
	const InnerGraph& m_nGraph;
	InnerGraph* m_pReverseGraph;
	typename DepthFirstVisit<Key, Value>* m_pDepthFirstVisit;
};

实现

构造

template<typename Key, typename Value>
StrongConnectGraph<Key, Value>::StrongConnectGraph(const InnerGraph& nGraph_)
	: m_nGraph(nGraph_), m_pReverseGraph(nullptr), m_pDepthFirstVisit(nullptr)
{

}

析构

template<typename Key, typename Value>
StrongConnectGraph<Key, Value>::~StrongConnectGraph()
{
	if (m_pReverseGraph != nullptr)
	{
		delete m_pReverseGraph;
		m_pReverseGraph = nullptr;
	}

	if (m_pDepthFirstVisit == nullptr)
	{
		delete m_pDepthFirstVisit;
		m_pDepthFirstVisit = nullptr;
	}
}

算法运行

template<typename Key, typename Value>
DataStruct::Array::DynArray<typename DepthFirstVisit<Key, Value>::Node*> StrongConnectGraph<Key, Value>::Run()
{
	DepthFirstVisit<Key, Value> _alDepthFirstVisit(m_nGraph);
	DataStruct::Array::DynArray<typename DepthFirstVisit<Key, Value>::Node*> _arrNodes = _alDepthFirstVisit.Run();
	_arrNodes.Sort([](typename DepthFirstVisit<Key, Value>::Node* pNode1_, typename DepthFirstVisit<Key, Value>::Node* pNode2_)->int
	{
		int _nRet = pNode1_->GetLastVisitTime() - pNode2_->GetLastVisitTime();
		if (_nRet > 0)
		{
			return -1;
		}
		else if (_nRet < 0)
		{
			return 1;
		}
		else
		{
			return 0;
		}
	});

	DataStruct::Array::DynArray<Key> _arrKeys;
	for (int _i = 0; _i < _arrNodes.GetSize(); _i++)
	{
		typename InnerGraph::Pair _nPair = _arrNodes[_i]->GetGraphNode()->GetPair();
		_arrKeys.Add(_nPair.m_nKey);
	}

	ReverseGraph<Key, Value> _alReverseGraph(m_nGraph);
	if (m_pReverseGraph != nullptr)
	{
		delete m_pReverseGraph;
		m_pReverseGraph = nullptr;
	}

	if (m_pDepthFirstVisit == nullptr)
	{
		delete m_pDepthFirstVisit;
		m_pDepthFirstVisit = nullptr;
	}

	try
	{
		m_pReverseGraph = new InnerGraph(_alReverseGraph.Run());
		m_pDepthFirstVisit = new DepthFirstVisit<Key, Value>(*m_pReverseGraph);
	}
	catch (...)
	{
		throw "out of memory";
		m_pReverseGraph = nullptr;
		m_pDepthFirstVisit = nullptr;
	}
	
	return m_pDepthFirstVisit->Run(_arrKeys);
}

算法目标&算法的性质证明

强连通分量算法:
1.对图G执行深度优先搜索,
2.对节点按结束时间递减排序,组成图中节点一个排列A
3.对图G的转置图G^t,按排列A中节点顺序,进行深度优先搜索

算法可能具备的性质&算法目标分析:
我们知道,若算法处理后,节点p的结束时间 > 节点q的结束时间
则,要么 p,q在主循环某个节点t的visit中被访问
此时,
a.1要么在访问链p->x1->...->xn->q中被访问
a.2要么在
t->x1->...->xk->y1->...->yn->q
 t->x1->...->xk->z1->...->zm->p
其中,对xk可达节点按顺序执行访问时,先访问y1,后z1
中被访问
b.要么p,q分别在主循环某节点t1,t2的visit中被访问
且t1在t2之后执行

算法运行后形成的访问链上任意两节点在G中是相互可达的

通过主循环,对节点t执行visit
此时图中节点只有状态unvisit和visited
对t执行完visit后
将完成在访问前状态为unvisit节点集合中,所有对t可达节点的访问
对于访问前状态为unvisit节点集合中,任意对t可达节点的k访问
设访问后形成的任意一条路径为:
t->x1->x2->...->xn->k

分析:t,x1

首先
易于知道,t.m_nEndTime > x1.m_nEndTime
然后,易于知道G中存在,x1->t的边

因为t.m_nEndTime > x1.m_nEndTime
所以,
在G中
1.要么 t,x1在主循环某个节点x的visit中被访问
此时,
a.1要么在访问链t->y1->...->yn->x1中被访问
此时,知道t~x1
综合,此种情况下,G中t~x1,又可x1~t
可知两个节点在G中相互可达。

a.2要么在
x->y1->...->yk->a1->...->an->x1
x->y1->...->yk->b1->...->bm->t
其中,对yk可达节点按顺序执行访问时,先访问a1,后b1
中被访问
下面证明不可能是这种情况
采用反证法
如果是这种情况,
则,G深度搜索访问到x1时,由于t未被访问且可由x1到达,故接着会访问t,这与现实不符和。
故x1,t不会属于这种情况

b.要么x1,t分别在主循环某节点t1,t2的visit中被访问
且t2在t1之后执行
下面证明不可能是这种情况
采用反证法
如果是这种情况
则,G深度搜索访问到x1时,由于t未被访问且可由x1直接到达,故接着会访问t,这与现实不符合。

综合
在G中存在
t~x1,x1~t

分析t,x2

首先
易于知道,t.m_nEndTime > x2.m_nEndTime
然后,易于知道G中存在,x2->x1的边
由于t,x1在G中相互可达。
故,G中存在x2->x1~t
因为t.m_nEndTime > x2.m_nEndTime
所以,
在G中
1.要么 t,x2在主循环某个节点x的visit中被访问
此时,
a.1要么在访问链t->y1->...->yn->x2中被访问
此时,知道t~x2
综合,此种情况下,G中t~x2,又可x2~t
可知两个节点在G中相互可达。

a.2要么在
x->y1->...->yk->a1->...->an->x2
x->y1->...->yk->b1->...->bm->t
其中,对yk可达节点按顺序执行访问时,先访问a1,后b1
中被访问
下面证明不可能是这种情况
采用反证法
如果是这种情况,
则,G深度搜索访问到x2时,
已知G存在路径
x2->x1->t

若此时,
x1已经被访问,
由于此时t尚未被访问,
若x1已经被访问。
则在访问x1时候,t对于x1是其直接可达且未被访问节点,
故,t会随后被访问。
这与t尚未被访问冲突。故此时x1尚未被访问。
若此时,
x1尚未被访问,x2访问时,
由于x1是其直接可达且尚未被访问节点,故随后会访问x1。
对x1访问时,由于t是其直接可达且尚未被访问节点。
故随后会访问t。
这和a.2.上述访问链冲突。
在假设a.2上述访问链存在下,将产生解释上的冲突。
故,a.2.上述访问链不可能存在。

b.要么x2,t分别在主循环某节点t1,t2的visit中被访问
且t2在t1之后执行
下面证明不可能是这种情况
采用反证法
如果是这种情况,
则,G深度搜索访问到x2时,
已知G存在路径
x2->x1->t

若此时,
x1已经被访问,
由于此时t尚未被访问,
若x1已经被访问。
则在访问x1时候,t对于x1是其直接可达且未被访问节点,
故,t会随后被访问。
这与t尚未被访问冲突。故此时x1尚未被访问。
若此时,
x1尚未被访问,x2访问时,
由于x1是其直接可达且尚未被访问节点,故随后会访问x1。
对x1访问时,由于t是其直接可达且尚未被访问节点。
故随后会访问t。
这和b.上述访问链冲突。
在假设b.上述访问链存在下,将产生解释上的冲突。
故,b.上述访问链不可能存在。
综合
在G中存在
t~x2,x2~t

分析t,x3

首先
易于知道,t.m_nEndTime > x3.m_nEndTime
然后,易于知道G中存在,x3->x2的边
由于t,x2在G中相互可达。
故,G中存在x3->x2~t
因为t.m_nEndTime > x3.m_nEndTime
所以,
在G中
1.要么 t,x3在主循环某个节点x的visit中被访问
此时,
a.1要么在访问链t->y1->...->yn->x3中被访问
此时,知道t~x3
综合,此种情况下,G中t~x3,又可x3~t
可知两个节点在G中相互可达。

a.2要么在
x->y1->...->yk->a1->...->an->x3
x->y1->...->yk->b1->...->bm->t
其中,对yk可达节点按顺序执行访问时,先访问a1,后b1
中被访问
下面证明不可能是这种情况
采用反证法
如果是这种情况,
则,G深度搜索访问到x3时,
已知G存在路径
x3->x2->x1->t

若此时,
x1已经被访问,
由于此时t尚未被访问,
若x1已经被访问。
则在访问x1时候,t对于x1是其直接可达且未被访问节点,
故,t会随后被访问。
这与t尚未被访问冲突。故此时x1尚未被访问。
若此时,
x2已经被访问,
由于此时x1尚未被访问,
若x2已经被访问。
则在访问x2时候,x1对于x2是其直接可达且未被访问节点,
故,x1会随后被访问。
进一步,x1访问时,会访问t。
这与t尚未被访问冲突。故此时x2尚未被访问。

若此时,
x1,x2尚未被访问,x3访问时,
由于x2是其直接可达且尚未被访问节点,故随后会访问x2。
对x2访问时,由于x1是其直接可达且尚未被访问节点。故随后会访问x1。
对x1访问时,由于t是其直接可达且尚未被访问节点。故随后会访问t。
这和a.2.上述访问链冲突。
在假设a.2上述访问链存在下,将产生解释上的冲突。
故,a.2.上述访问链不可能存在。

b.要么x3,t分别在主循环某节点t1,t2的visit中被访问
且t2在t1之后执行
下面证明不可能是这种情况
采用反证法
可类似证明b访问链不可能存在
故,b.上述访问链不可能存在。
综合
在G中存在
t~x3,x3~t

分析t,x4

...

分析t,xn

...

分析t,k

...

综合

对算法处理后,形成的一条关系链,
关系链上任意两个节点在G中均是相互可达的。

下面接着证明

若G中存在,相互可达的节点p,q,则,在运行本算法后,p,q间必然存在对应的链将两者连接

证明:
G中存在p~q,q~p
则,G^T中也存在p~q,q~p

对G^T中执行深度访问时,
每次对节点t执行访问
会访问到所有G^T中状态为unvisit状态节点中所有从t可达的。

假设连接q~q的任一路径上首个被访问节点为k
则k是可以连接p,q的路径上首个被访问的节点
则此时p,q属于G^T中状态为unvisit状态节点中所有从k可达的。
所以会被k访问到。
所以,执行后p,q将率属于同一颗树。

算法性质总结

综合上述两个证明过程
可知,本算法执行后
形成的多个分别以某个节点为根的树,同一棵树中节点在G中相互可达
不同棵树中节点p,q无法在G中相互可达。
这样,同一颗树中的节点集合构成了G的一个强连通分量
算法运行后,一次求出了G中所有强连通分量。
原创文章 134 获赞 87 访问量 6万+

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/105781928
今日推荐