Tarjan 的应用

Tarjan

在有/无向图中,如果两个节点可以相互到达,则称这两个节点强连通[Strongly
connected],如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量 [Strongly connected components]

Tarjan 的发明者Robert Tarjan是 一位伟大的计算机科学家。他发明的LCA,Tarjan 知道现在一直都是数据结构的基础根基。由于他杰出的贡献 ,让他也同样获得了计算机界的诺贝尔奖——图灵奖。

但究竟什么是 强连通分量?什么是强连通图?很多人都爱用下面的图。。。

虽然很丑。不过说明了一些 本质?
还是下面的比较好

Graph 1 就是一个强连通图,因为这4个点可以两两任意 相互到达。但是Graph 2 就不是因为 4 不能到达其余任意一个点。


Algorithm:

在我看来,Tarjan 就是一个很 玄学的东西。甚至不需要你去理解为什么要这么做,把代码记熟,要求的东西都能求出来了。但还是说说吧。

Tarjan算法是基于对图深度优先搜索的算法。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。

具体见代码:

Code:

void Tarjan(int rt)
{
    dfn[rt]=low[rt]=++dep;
    stack[++top]=rt;
    for(int i=head[i];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        if(dfn[to]==0)
        {
            Tarjan(to);;
            low[rt]=min(low[rt],low[to]);
        }
        if(belong[to]==0)
        {
            low[rt]=min(low[rt],dfn[to]);
        }
    }
    if(low[rt]==dfn[to])
    {
        scc_cnt++;
        int t=0,v;
        do
        {
            t++;
            v=stack[top--];
            belong[v]=scc_cnt;
        }while(v!=rt);
        scc_num[scc_cnt]=t;
    }
}
  • scc_cnt表示图中的强连通块的个数
  • belong[i]表示i点所在强连通图中的编号
  • scc_num[i]表示第i号强连通图 中的元素个数

    对于无向图的Tarjan大同小异,只要多传一个变量记录rt的父亲节点就好了、同时多了一些概念比如 割点、割边(桥)。但也十分简单 。


应用

Tarjan 的应用十分广泛 。除了在强联通图中的一些性质外,它还可以判断确定某些集合关系。
☀举个例子,K国有N个地区,每个地区间可以免费通行,而到别的地区就需要花费相应的代价。现在想让你求从ST到 ED间的最短路时就不能简单用Dijkstra或者SPFA。而需要先Tarjan缩点后重新建图,再跑最短路。

☀Tarjan 的另一个应用就是有关的 应用:
在有向图中,如果给定N个人以及中的M个关系。然后现在让你确定一个/些点让它与其它各点都有关系。而我们的解决方法就是先缩点,把能够 互相到达[即与本集合中的点都有关系]的点缩成一个点。然后出度为0的集合中的点就是我们要求的答案。

☀无向图中的双联通分量中也有很多应用:比如删掉一个点让连通图的数量最大。那么显然删掉 割点 就可以了。

☀有的时候,问题可能没有那么明显:USACO中有一道题,求的是在一张无向图中,最少加几条边,能让任意两点间,至少有两条不重复的路径相互到达。乍一看可能不知道该怎么想,但是随着分析的深入我们会发现,在一个双联通分量图中,任意两个点都有两条路径相互到达。所以我们就可以把这道题转化为 最少加入多少边让图变成 边-双。
而我们的解决方法 就是在缩点之后把入度为1的点集计数[sum],(sum+1)/2 就是答案。

☀//首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

☀还有就是可以用 Tarjan 离线求LCA。
。。。 。。。


小结

总之,Tarjan 就是解决 图论问题的一种方法而已。或者说Tarjan只是我们简化问题的一种手段。真正考验我们的不是怎么去写代码,而是怎么通过各种手段简化问题,让数据范围更容易接受。这才是我们开发算法,编程的目的 。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值