Tarjan 的应用

来源:互联网 发布:手机编曲软件中文版 编辑:程序博客网 时间:2024/05/22 01:50

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
原创粉丝点击