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. Python-认识正则表达式-53

    # 计算器# re模块# 正则表达式 —— 字符串匹配的# 学习正则表达式# 学习使用re模块来操作正则表达式 #判断手机号是否符合要求 while True: phone_number = inpu ...

  2. java的instanceof关键字

    java 中的instanceof 运算符是用来判断对象是否是 特定类或这个特定类的子类 的一个实例. 用法: result = object instanceof class 参数: Result: ...

  3. 数学基础IV 欧拉函数 Miller Rabin Pollard's rho 欧拉定理 行列式

    找了一些曾经没提到的算法.这应该是数学基础系最后一篇. 曾经的文章: 数学基础I 莫比乌斯反演I 莫比乌斯反演II 数学基础II 生成函数 数学基础III 博弈论 容斥原理(hidden) 线性基(h ...

  4. HDU - 1754 线段树-单点修改+询问区间最大值

    这个也是线段树的经验问题,待修改的,动态询问区间的最大值,只需要每次更新的时候,去把利用子节点的信息进行修改即可以. 注意更新的时候区间的选择,需要对区间进行二分. #include<iostr ...

  5. Python删除list里面的重复元素的俩种方法

    1.使用set函数  In [116]: a=[1,2,3,2,1,3,4,5,6,5] In [117]: set(a) Out[117]: {1, 2, 3, 4, 5, 6} 2.使用字典函数 ...

  6. 了解sso原理

  7. 我的集合学习笔记--ArrayList

    一,ArrayList 实现自己的ArrayList:主要是添加方法,理解自动扩容机制 代码+注释 package com.amazing.jdk.learn2List.list_08_13; /** ...

  8. shell脚本--CGI获取请求数据(GET / POST)

    Case 1: 获取地址栏传递的参数(即通过GET方式) CGI的环境变量中有个QUERY_STRING,可以获取地址栏传递的参数,该参数可以是手动加上的,也可以是通过表单的get方式提交的,比如下面 ...

  9. java 工具

    JClassLib 4.2 发布了,该版本支持 Java 7 和 Java 8 的类文件属性查看. JClassLib不但是一个字节码阅读器而且还包含一个类库允许开发者读取,修改,写入Java Cla ...

  10. [转帖]Runtime, Engine, VM 的区别是什么?

    这就是个WiFi和WLAN关系的问题嘛.Runtime是指用于支持程序运行时的组件,它可以是个Engine和/或VM.VM是一种系统抽象,它提供代码执行所需的API环境.Engine是一种处理抽象,它 ...