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. 小记Java时间工具类

    小记Java时间工具类 废话不多说,这里主要记录以下几个工具 两个时间只差(Data) 获取时间的格式 格式化时间 返回String 两个时间只差(String) 获取两个时间之间的日期.月份.年份 ...

  2. 从 0 到 1 实现 React 系列 —— 5.PureComponent 实现 && HOC 探幽

    本系列文章在实现一个 cpreact 的同时帮助大家理顺 React 框架的核心内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/PureComponent/HOC/...) ...

  3. OSGI 环境搭建

    第一步,打开eclipse,新建一个plugin工程,如下图所示 第二步,输入工程的名字,并且在Target Platform中选择an OSGI framework中选中standard,如下图所示 ...

  4. Python学习第三篇——逻辑判定

    request_foods=["tomato","beaf","milk"] for elements in request_foods: ...

  5. Codeforces Round #534 (Div. 2)D. Game with modulo-1104-D(交互+二分+构造)

    D. Game with modulo time limit per test 1 second memory limit per test 256 megabytes input standard ...

  6. Redis趣谈一则

    今天看代码,无意中发现Redis中的一行注释: ; /* The world is full of Solaris Fixes */ 这行代码在bio.c文件中. 看来程序员对操作系统多样性吐槽多多啊 ...

  7. 在做stark中一些反射的问题。

    hasattr(obj,name): 判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False.需要注意的是name要用括号括起来   1 ...

  8. 【学习总结】Git学习-参考廖雪峰老师教程九-使用码云

    学习总结之Git学习-总 目录: 一.Git简介 二.安装Git 三.创建版本库 四.时光机穿梭 五.远程仓库 六.分支管理 七.标签管理 八.使用GitHub 九.使用码云 十.自定义Git 期末总 ...

  9. CDH 6.0.1 集群搭建 「Process」

    这次搭建我使用的机器 os 是 Centos7.4 RH 系的下面以流的方式纪录搭建过程以及注意事项 Step1: 配置域名相关,因为只有三台机器组集群,所以直接使用了 hosts 的方法: 修改主机 ...

  10. Fiddler 学习笔记---命令、断点

    输入命令框: 1 输入 ?51testing  高亮显示对应记录 2 >10 选择body大于10的记录 3 <10 选择body<10的记录 4 =200 选择result=200 ...