Tarjan算法是由美国著名计算机专家发明的,其主要特点就是可以求强连通分量和缩点·割点。

而强联通分量便是在一个图中如果有一个子图,且这个子图中所有的点都可以相互到达,这个子图便是一个强连通分量,并且很显然,这个强连通分量里的任何点组成的集合都可以相互到达,为了方便,我们不叫它们为强连通分量,而割点就是如果把这个点去掉,图就不会联通,同理割边就是把这个边去掉图就不会联通。


首先是用tarjan求强连通分量:

其中最重要的两个数组便是dfn和low,分别表示被搜索到的时间戳和在栈中最早的点的次序号。(也可以认为在搜索树中最小的子树根)就像是这个子树的父节点的时间戳,如果它的节点最小这样的话我们就要维护使它成为这个子树的父节点(因为父节点的他的时间戳肯定比他的子树小)。

我们将某个图进行一下dfs遍历一下,发现每条边都指向dfn比自己大的边,但是2——1这条边除外,因为就这一个边是一条回边,并且2没有其他的出边,再次搜索到1时dfn[1]==low[1],那此时1,2,3都在栈中比1相等或靠上的位置,那把1以上的位置的所有点都弹出并记录成一个强连通分量。

我们知道dfn肯定是不变的,但是low可能会改变,当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。(就是这个子树都回溯完了,并且并没有以u为起点的出边了,且他是这个子树中的根节点)所以栈中u以上的点根据深搜性质所有点都是他的子树,那包括他以上的所有点都是一个强连通分量。

由定义可以得出

Low(u)=Min
{
   本身,
   Low(v),//我们将v以u为起点的一条边的终点。如果v这个点并没有搜索过,那我们先把v这个点tarjan一下,然后根据定义更新一下low值.(1)
   DFN(v)//如果v这个点搜索过且这个点在栈中,说明u到v有一条由子节点指向某个祖先的边(2)
 }

有一个对上面三行的解释:

当出现第一种情况时,说明再将v点深搜一遍之后,u的low值是u的low值和v的low值的最小值。

为什么呢,因为v可能会回去,也可能继续向下搜索没有被访问过的点(即dfn还没有确定的点),根据定义,low值一定是最早的点,所以就需要更新。

当出现第二种情况时,说明low[v]还在栈中,且并没有更新,v点的时间戳比现在的时间戳要小,因此也需要进行更新。

上伪代码:

void tarjan(int u)//当前节点
{
    dfn[u]=low[u]=++cnt;//该节点本身是一个强联通分量
    节点入栈;
    vis[u]=true;//当前节点已入栈
    for(遍历该节点所有出边)
    {
        int v=当前边的终点;
        if (!dfn[v])
        {
            tarjan(v);//深度优先遍历
            low[u]=min(low[u],low[v]);
        }
        else low[u]=min(dfn[v],low[u]);
    }
    if (low[u]==dfn[u])
    {
        while(栈顶!=v)
        {
            染色;
            出栈;
        }
    }
    染色;
    出栈;
}

题目(牛的舞会)

这个题是一个裸的求强连通分量的个数的题。

首先我们先建好图,建好图之后我们就可以用Tarjan算法来求强连通分量了,我们先明确好几个变量和他们的用途,最重要的就是dfn和low数组了,结构体e数组是邻接表,point是总的强连通分量的个数,stack是强连通分量的栈,vis是判断是否在栈中,top是栈顶。主函数就不讲了,主要看tarjan函数,首先我们先把每一个点的

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
],n,m,dfn[],low[],tot,point,cnt,top,stack[],vis[];
struct cym
{
    int from,to,next;
}e[];
void add(int f,int t)
{
    e[++cnt].from=f;
    e[cnt].to=t;
    e[cnt].next=lin[f];
    lin[f]=cnt;
}
void tarjan(int u)
{
    low[u]=dfn[u]=++tot;
    stack[++top]=u;
    vis[u]=;
    for(int i=lin[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        ;
        point++;
        ;
        while(v!=u)
        {
            total++;
            v=stack[top--];
            vis[v]=;
        }
        )
        point--;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    ;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    ;i<=n;i++)
        if(!dfn[i])
        tarjan(i);
    printf("%d",point);
    ;
}

会了强联通分量之后还能干什么呢,就可以缩点了,因为一个强联通分量里的点都可以相互到达,所以他们相当于一个点,在DP或搜索的时候,如果题目让你求一个最大值,那我们就可以缩点,因为不走白不走。该怎么缩点呢,我们要把每一个强联通分量里的所有点都染上同一种颜色,然后把每一个强联通分量都变成一个新点,然后建一个新图,然后就由原来的图变成了一个新图。

还可以求割点

Tarjan求强连通分量,缩点,割点的更多相关文章

  1. tarjan求强连通分量+缩点+割点以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  2. tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  3. HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  4. 【BZOJ1051】1051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点

    Description 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎. 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认 ...

  5. Tarjan求强连通分量 缩点

    强连通分量的定义: 在一张有向图中,如果两个点u,v之间能相互到达则称这两个点u,v是强连通的,在这个基础上如果有向图G中的任意两个顶点都强连通,那么称图G是一个强连通图.有向非强连通图的极大强连通子 ...

  6. tarjan求强连通分量+缩点 模板

    #define N 100100 #define M 200200 int n,m; int id,index; //id表示缩点后点的id,index表示进行tarjan算法时访问的点先后 int ...

  7. Tarjan求强连通分量、求桥和割点模板

    Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using n ...

  8. UESTC 901 方老师抢银行 --Tarjan求强连通分量

    思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大.所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个D ...

  9. CCF 高速公路 tarjan求强连通分量

    问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的 ...

随机推荐

  1. Omi v1.0震撼发布 - 开放现代的Web组件化框架

    原文链接--https://github.com/AlloyTeam/omi 写在前面 Omi框架经过几十个版本的迭代,越来越简便易用和强大. 经过周末的连续通宵加班加点,Omi v1.0版本终于问世 ...

  2. Python学习第四篇——列表访问与判定

    avilable_foods=["soup","beaf","noddle","pepper"] request_foo ...

  3. Linux下php安装redis扩展(redis已经安装)

     1. 下载需要的php操作redis的扩展包 (1).切换到 cd  /usr/local/src (2).   wget https://github.com/nicolasff/phpredis ...

  4. mybatis的mapper注入失败

    因为处在两个不同的资源文件夹下: 导致classpath无法加载其中一些文件,所以修改为classpath*后顺利进行. <!-- 加载spring容器 --> <!-- neede ...

  5. Dapper.NET

    关于Dapper.NET的相关论述   年少时,为何不为自己的梦想去拼搏一次呢?纵使头破血流,也不悔有那年少轻狂.感慨很多,最近事情也很多,博客也很少更新了,毕竟每个人都需要为自己的生活去努力. 最近 ...

  6. 【学习总结】Master课程 之 虚拟化与云计算

    Section 1- Cloud Computing Introduction-云计算介绍 1-What can Cloud Computing do? - 云计算可以做什么? 服务模式:美国国家标准 ...

  7. 解决linux用户切换失败 su:execute /usr/bin 没有权限

    问题描述: 回宿舍前,在root用户中安装fish,并修改其shell为fish.回宿舍之后,在图形界面用root用户进行登陆,莫名其妙登陆失败.没有任何提示信息,直接回到登陆界面.用非root用户登 ...

  8. 5 Expressing future time

    1 英语中表达将来的时间有四种主要方式:be going to, will, 现在进行时,一般现在时. 2 Make a prediction. 若要预测将来, 可以使用 be going to 或者 ...

  9. K3CLOUD数据权限授权

    1.定义角色,把用户放入角色内 2.设置数据规则 3.设置业务对象功能授权

  10. vue.js实战——vue 实时时间

    created:实例创建完成后调用,此阶段完成了数据的观测等,但尚未挂载,$el还不可用,需要初始化处理一些数据时会比较有用. mounted:el挂载到实例上后调用,一般我们的第一个业务逻辑会在这里 ...