关于tarjan算法的应用

目前为止

我知道tarjan算法可以用来求取有向图的强连通分量

还有就是无向图的双连通分量

下面记录注意事项


   首先强连通分量是这样的一个有向图,里面任意的两点都可以互相通达,每条边都只经过一次,而不管这两条路径中是否经过相同的点。换句话说,也就是,在这个图中,删去任意一条边,任意的两点至少有一个点可以到达另外一个点。

    此外 ,强连通分量是对点的分割,而后面说的双连通分量是对边的分割。  

Low[x]表示的是x这个点能连接到的先序最小的点

Dfn[x]表示x这个点的dfs的先序值

详细请看程序解释:

void dfs(int x)
{
   low[x]=dfn[x]=++len; //标记默认值
   stk[++top]=x;    //把当前的点加入堆栈
   for(int q=beg[x];q;q=e[q].next) //遍历所有连接到的点
   {
   int v=e[q].v;
   if(dfn[v]==0) dfs(v);
   if(low[v]<low[x]) low[x]=low[v];//取子孙中能连接到的最先访问的点
   }  
   if(low[x]<dfn[x]) return ; //若子孙能连接到祖先,那么不能从当前的点把强连通分支分出去
   ++scc;//否则就可以以当前的点为界线,把它下面的没有连接到比它更早的
   //点和它本身都加入到新的分支中,并标号
    do{ 
id[w=stk[top--]]=scc;
low[w]=n;//这里要注意的是,在有向图中是存在横边的,所以
//就需要把加入SCC的点的low都赋为n,解决了横向边的问题。
}while(w!=x);
}


双连通分量:

  求双连通的方法和求SCC很类似,不过这里需要注意几个地方:

  一、Low值相同的话,有可能是在同一个双连通块中,也可能在两个不同的连通块,不过这两个连通块是由一个割点连起来的,但如果这两个连通块是由一条桥连接的,那么它们的low值肯定不同。

  所以可以直接用low值来判断桥。

  二、此外,如果需要判断割点,那么对根:在dfs树上有2个或以上的儿子,那么根是割点;对于其他节点u,假如存在一个儿子v,使得low[v]>=dfn[u],那么u是割点。

  三、求连通块,由于双连通块是对边的分割,所以这里的堆栈是储存边的,具体步骤和上面的类似,每次都把边加入堆栈中,在dfs儿子节点后,如果当前的节点是割点,那么就可以以当前节点为界线,划分出双连通块。

void dfs(int x,int fat)
{
   low[x]=dfn[x]=++len;      
   for(int q=beg[x];q;q=e[q].next)
if(e[q].v!=fat)
{
   int v=e[q].v;
   if(dfn[v]==0)  
{
      dfs(v,x);
  if(low[v]<low[x]) low[x]=low[v];
   }
   else if(dfn[v]<low[x]) low[x]=dfn[v];
   }  
}









































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值