Tarjan的求双连通分量算法

哎~气死我了!昨天晚上都写好了……一不小心把网页关了,写的全没了……MD

什么是双连通分量DCC(Double connected component)?

首先说一下一个无向连通图,若去掉任一点或任一边都不影响该图的连通性(本来是连通的,现在仍连通),那么该图是一个双连通图(该图的DCC只有一个即本身)。

DCC是一个无向连通图(注意是无向连通图不是有向图,别把强连通分量与他们搞混了!)的子图,该子图是一个双连通图(尽可能大的双连通图,也就是尽可能包含更多的点)。也就是说一个无向连通图的DCC需要满足三个条件:1.它是该无向连通图的子图 2.该子图是一个双连通图 3.使该子图尽可能的大

什么是割点、桥?

一个无向连通图,去掉一点或一边后影响了改图的连通性(本来是连通的,现在不连通了),则该点就是割点或该边就是桥。

求DCC的算法的分析,我就不说了……就是说了也难以理解,直接贴上加注释的code,你自己画个图,跟着程序走一遍,慢慢体会体会!

//----------DCC------------------

int dfn[MAXNODE],low[MAXNODE],index;//dfn记录各点被访问次序,low是追溯到DCC的根节点
//的dfn的值,当根节点的某个直接儿子节点的low值大于或等于根节点的dfn的值时,就可以从
//栈中取值了,直到取到根节点为止时一个DCC

int stack[MAXNODE],top;//栈:用深搜搜索节点并依次存储各个节点—以便于找到DCC(即当
//发现环时就是一个DCC,用low标记的,从该栈中取值取到该根节点为止)

int id_dcc[MAXNODE],cnt_dcc;//id_dcc:名副其实即DCC的id(编号),存储各节点的所在的
//编号(就是你给他们编的号,从1-n)cnt_dcc就是编号下标!

int father[MAXNODE];//由于求DCC是在一个无向连通图中,即为双向的图,该father就是为了
//防止某一节点又访问上一个节点(上一个节点搜出该节点)

void DFS_DCC(int cur)
{
int next; //next为cur节点下的节点
dfn[cur]=low[cur]=++index;
stack[
++top]=cur;
for(Node *p=G[cur];p;p=p->next)
{
next
=p->num;
if(!dfn[next])
{
father[next]
=cur; //额,可以不用。。
DFS_DCC(next);
if(low[next]<low[cur]) //更新low使每一个DCC中的low的值==根节点low值
low[cur]=low[next];
if(low[next]>=dfn[cur])//当发现节点cur的儿子节点next的low值>=dfn[cur]
{ //则就要取栈,即是时候取出DCC了。为什么?因为不
cnt_dcc++; //这样就不对了^_^!(具体原因,自己举几个例子try)
do
{
next
=stack[top--];
id_dcc[next]
=cnt_dcc;
}
while(next!=cur);
top
++; //这里为什么要++因为连着DCC是有共同节点的(举例try)
//不++肯定要出错!也许我这code跟别人不一样,其实
//思想都一样,只是具体实现的code有小小的差异罢了
}
}
else if(next!=father[cur] && dfn[next]<low[cur])
{
//呃呃呃!其实不用这个father数组都可以了,只需
//dfn[next]<low[cur]就行了
low[cur]=dfn[next];
}
}
}
void solve()
{
index
=top=cnt_dcc=0;
memset(dfn,
0,sizeof(dfn));//初始化各下标及dfn
DFS_DCC(1);//由于是无向连通图,只需深搜一个节点就都可以都到了
}

上面的是求DCC,有时候要求割点,求桥,你根据定义自己想想……都差不来啊!

可能解释的不够清楚,有什么问题?可以问我饿!或者发现有什么不对或不好的地方,欢迎指正!

不过我也只是知道这样实现,并不真正懂得为什么。你如果问我为什么是这样,它的原理是什么?我会给你说:因为只有这样才能实现,它原理就在实现中^_^!如果大虾你理解的深的话……希望能给小弟分享一下!

原文地址:https://www.cnblogs.com/fornever/p/2179448.html