E(Tarjan)

原创 2018年04月17日 20:45:01

为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。 
Input输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。 
Output对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。 
Sample Input
3 3
1 2
2 3
3 1
3 3
1 2
2 3
3 2
0 0
Sample Output
Yes
No

问是否只存在一个强连通图。

有两个连通图就说明有的点没连载一块,就不能对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。 

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。Tarjan算法有点类似于基于后序的深度遍历搜索和并查集的组合,充分利用回溯来解决问题。
在Tarjan算法中为每个节点i维护了以下几个变量:
DFN[i]:深度优先搜索遍历时节点i被搜索的次序。
low[i]:节点i能够回溯到的最早位于栈中的节点。
flag[i]:标记几点i是否在栈中。

Tarjan算法的运行过程:
1.首先就是按照深度优先搜索算法搜索的次序对图中所有的节点进行搜索。
2.在搜索过程中,对于任意节点u和与其相连的节点v,根据节点v是否在栈中来进行不同的操作:
*节点v不在栈中,即节点v还没有被访问过,则继续对v进行深度搜索。
*节点v已经在栈中,即已经被访问过,则判断节点v的DFN值和节点u的low值的大小来更新节点u的low值。如果节点v的 DFN值要小于节点u的low值,根据low值的定义(能够回溯到的最早的已经在栈中的节点),我们需要用DFN值来更新u 的low值。
3.在回溯过程中,对于任意节点u与其子节点v(其实不能算是子节点,只是在深度遍历的过程中,v是在u之后紧挨着u的节点)的   low值来更新节点u的low值。因为节点v能够回溯到的已经在栈中的节点,节点u也一定能够回溯到。因为存在从u到v的直接路   径,所以v能够到的节点u也一定能够到。
4.对于一个连通图,我们很容易想到,在该连通图中有且仅有一个节点u的DFN值和low值相等。该节点一定是在深度遍历的过程中,该连通图中第一个被访问过的节点,因为它的DFN值和low值最小,不会被该连通图中的其他节点所影响。下面我们证   明为什么仅有一个节点的DFN和low值相等。假设有两个节点的DFN值和low值相等,由于这两个节点的DFN值一定不相同 (DFN值的定义就是深度遍历时被访问的先后
   次序),所以两个的low值也绝对不相等。由于位于同一个连通图中,所以两个节点必定相互可达,那么两者的low值一定会   被另外一个所影响(要看谁的low值更小),所以不可能存在两对DFN值和low值相等的节点。

   所以我们在回溯的过程中就能够通过判断节点的low值和DFN值是否相等来判断是否已经找到一个子连通图。由于该连通图中   的DFN值和low值相等的节点是该连通图中第一个被访问到的节点,又根据栈的特性,则该节点在最里面。所以能够通过不停   的弹栈,直到弹出该DFN值和low值相同的节点来弹出该连通图中所有的节点。

一个Tarjan模板

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 11000
#define M 110000
using namespace std;
struct node
{
    int next,v;
}e[M];
int head[N],dfn[N],low[N],v[N],q[N],cnt,scnt,top,n,m,blong[N];
void init()
{
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    cnt=top=scnt=0;
}
void add_edge(int u,int v)
{
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void tarjan(int u)
{
    int t;
    dfn[u]=low[u]=++cnt;//初始化两个值,自己为能找到的最先访问的祖先
    v[u]=1;//标记为已经在栈中
    q[top++]=u;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int c=e[i].v;
        if(!dfn[c])//如果点i没有被访问过
        {
            tarjan(c);  //递归访问
            low[u]=min(low[u],low[c]); //更新能找的到祖先
        }
        else if(v[c])//这个判断条件很重要,这样可以避免已经确定在其他联通图的v,因为u到v的单向边而影响到u的low
            low[u]=min(low[u],dfn[c]);

    }

    //往后回溯的时候,如果发现DFN和low相同的节点,就可以把这个节点之后的节点全部弹栈,构成连通图
    if(dfn[u]==low[u])
    {
        scnt++; //记录连通图的数量
        do
        {
            t=q[--top];//依次取出,直到u
            v[t]=0; //设置为不在栈中
            blong[t]=scnt;
        }while(t!=u);
    }
}
void solve()
{
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
}
int main()
{
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        init();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        solve();
        cout<<(scnt==1?"Yes":"No")<<endl;
    }
}

求强连通分量的Tarjan算法

  • 2011年09月17日 22:37
  • 118KB
  • 下载

HDU6165 FFF at Valentine(并查集+tarjan缩点+拓扑排序)

题目:
  • cyf199775
  • cyf199775
  • 2017-08-23 00:02:38
  • 261

tarjan算法原理介绍

证明比较繁琐,仔细检查了应该没有大错,记录一下证明过程。 强连通分量定义: 在有向图中,强连通分量的定义是:有向图的某个子图,其中任意两个点之间可以互达。 强连通分量的定理: 定理1:...
  • zakheav
  • zakheav
  • 2015-06-09 11:22:25
  • 2402

强连通算法--Tarjan个人理解+详解

首先我们引入定义: 1、有向图G中,以顶点v为起点的弧的数目称为v的出度,记做deg+(v);以顶点v为终点的弧的数目称为v的入度,记做deg-(v)。 2、如果在有向图G中,有一条有向道路,则v称为...
  • mengxiang000000
  • mengxiang000000
  • 2016-06-14 17:31:12
  • 6043

Tarjan算法求强连通分量总结

Tarjan算法求强连通分量总结 首先明确强连通分量的概念:如果图中的任意两个点都能互相到达,则为强连通分量。极大强连通分量:不被其它任何强连通分量包含的强连通分量。 强连通分量主要与两种边有关:...
  • MrH929
  • MrH929
  • 2016-07-18 19:12:21
  • 629

Tarjan算法三大应用之强连通分量

Tarjan是一个对图的分析的强有力的算法,主要应用有:有向图的强连通分量、无向图的割点桥与双连通分量、LCA(最近公共祖先)基本概念下面主要介绍tarjan算法在强连通分量中的应用。首先我们需要知道...
  • mmy1996
  • mmy1996
  • 2017-02-23 11:43:32
  • 733

[hdu1269]Tarjan裸题

迷宫城堡Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi...
  • youhavepeople
  • youhavepeople
  • 2017-03-29 09:09:53
  • 323

震惊!史上最全的tarjan模板!99%的人都不知道!

tarjan
  • chai_jing
  • chai_jing
  • 2017-04-12 21:16:20
  • 846

无向图 tarjan 总结

说到这个无向图,就没强连通或者极大连通了,因为边都是互相相连的,但是你也可以拆成两条有向边来做,但是删去,或者处理这条边的时候,要记住同时把这两条边有向边给除去掉。 割点:没了这个点,这个无...
  • qq_35607232
  • qq_35607232
  • 2016-07-19 21:38:20
  • 567

Tarjan强连通分量详解补充

这是一篇关于Tarjan的算法讲解,个人觉得不错,来展示一下分享。。。由于不知怎么转载。。(别打脸,蒟蒻一枚),于是自己重新整理后再发表 ...
  • HownoneHe
  • HownoneHe
  • 2016-05-25 20:28:27
  • 1021
收藏助手
不良信息举报
您举报文章:E(Tarjan)
举报原因:
原因补充:

(最多只允许输入30个字)