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. 追源索骥:透过源码看懂Flink核心框架的执行流程

    li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt, ...

  2. Web测试和App测试有什么区别

    WEB测试和App测试从流程上来说,没有区别.都需要经历测试计划方案,用例设计,测试执行,缺陷管理,测试报告等相关活动.从技术上来说,WEB测试和APP测试其测试类型也基本相似,都需要进行功能测试.性 ...

  3. Python-爬虫的基本原理

    什么是爬虫 爬虫就是请求网站并提取数据的自动化程序.其中请求,提取,自动化是爬虫的关键!下面我们分析爬虫的基本流程 爬虫的基本流程 发起请求通过HTTP库向目标站点发起请求,也就是发送一个Reques ...

  4. Python _内置函数3_45

    reversed: #reversed() l = [1,2,3,4,5] l.reverse() print(l) #改变了原来的列表 l = [1,2,3,4,5] l2 = reversed(l ...

  5. stark组件的增删改(新)

      1.效果图 2.详细步骤解析 3.总结.代码   1.效果图 增 删除 改 2.详细步骤解析 1.构造增删改查url,反向解析 2.ModelForm定制add.edit页面 3.starak中的 ...

  6. 软件工程(FZU2015) 赛季得分榜,第七回合

    SE_FZU目录:1 2 3 4 5 6 7 8 9 10 11 12 13 积分规则 积分制: 作业为10分制,练习为3分制:alpha30分: 团队项目分=团队得分+个人贡献分 个人贡献分: 个人 ...

  7. Access使用记录

    iif函数 此函数类似编程语言中的双目运算符,官方解释如下: 在任何可以使用表达式的位置均可使用 IIf.您可以使用 IIf 确定另一个表达式为 True 还是 False.如果表达式为 True,则 ...

  8. Nginx三部曲(3)SSL

    我们将告诉你 Nginx 的运作模式.蕴含的概念,怎样通过调优 Nginx 来提高应用性能,或是如何设置它的启动和运行. 这个教程有三个部分: 基本概念 —— 这部分需要去了解 Nginx 的一些指令 ...

  9. laravel get和all区别

      get ,all 都可以获取到模型 all 是直接获取所有,get 是在添加了许多约束之后获取模型,get前面如果不加约束条件的话,效果与all等同

  10. 2 Modals of necessity

    1 情况动词must 和词组have to, need to ,have got to 都表示必须做某事或者要求做某事. need to  have to  must have got to When ...