强连通原理

强连通原理

用途:缩点&最小点基问题

原图经强连通缩点后变成了一个有向无环图。有向无环图变成强连通图只需增加max(g,h)条有向边即可(G为出度为0的节点数,H为入度为0的节点数,特别地当缩点后的图只有一个点时,答案为0

数组定义:

dfn[v]为遍历到点v的时间

low[v]开始遍历点v时初始化为dfn[v],遍历完点v时则保存所有与邻接点u的low[u]最小值

伪代码:

tarjan(u){//为节点u设定次序编号和Low初值

  DFN[u]=Low[u]=++Index

  Stack.push(u)          // 将节点u压入栈中

  for each (u, v) in E    // 枚举每一条边

    if (v is not visted) //如节点v未被访问

        tarjan(v) // 继续向下找

        Low[u] = min(Low[u], Low[v])

    else if (v in S) // 如果节点u还在栈内

        Low[u] = min(Low[u], DFN[v])

               if (DFN[u] == Low[u]) //若节点u是强连通分量的根

                              repeat v = S.pop   //将v退栈

       print v       //v为该强连通分量中一个顶点

  until (u== v)

}

算法模拟:如下图

从1进入 DFN[1]=LOW[1]=++index-1

入栈 1

由1进入2 DFN[2]=LOW[2]=++index-2

入栈 1 2

由2进入3 DFN[3]=LOW[3=++index-3

入栈 1 2 3

由3进入 6 DFN[6]=LOW[6]=++inde-4

入栈 1 2 3 6

6无出度,之后判断 DFN[6]==LOW[6]

说明6是个强连通分量的根节点:

6及6以后的点出栈。

栈: 1 2 3

退回节点3

Low[3] = min(Low[3], Low[6]) LOW[3]还是 3

节点3 也没有再能延伸的边了

判断 DFN[3]==LOW[3]

说明3是个强连通分量的根节点:

3及3以后的点 出栈。

栈: 1 2

之后退回 节点2 嗯?!往下到节点5

DFN[5]=LOW[5]=++index-5

入栈 1 2 5

结点5 往下找,发现节点6 DFN[6]有值,被访问过及不在栈中。就不管它。

继续 5往下找,找到了节点1 他爸爸的爸爸。。DFN[1]被访问过并且还在栈中,说明1还在这个强连通分量中,值得发现

Low[5] = min(Low[5], DFN[1])

确定关系,在这棵强连通分量树中,5节点要比1节点出现的晚,故5是1子节点

LOW[5]= 1

由5继续回到2

Low[2] = min(Low[2], Low[5])LOW[2]=1;

由2继续回到1 判断

Low[1]=min(Low[1],Low[2]) LOW[1]还是 1

1还有边未走。发现节点4,访问节点4

DFN[4]=LOW[4]=++index-6

入栈 1 2 5 4

由节点4,走到5,发现5被访问过,5在栈里

Low[4] = min(Low[4], DFN[5]) LOW[4]=5

说明4是5的一个子节点。

由4回到1.

回到1,判断

Low[1]=min(Low[1], Low[4]) LOW[1]还是1

判断 LOW[1] == DFN[1]

相等说明以1为根节点的强连通分量已找完,将栈中1及之后进栈的所有点出栈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值