搞过OI的对tarjan这个人大概都不陌生。这个人发明了很多神奇的算法,在OI届广被采用。

他最广泛采用的三个算法都是和$dfn$,$low$相关的。

有向图求强连通分量

其实说直白点,就是缩点。用得比较多的就是把一个有向有环图变为一个DAG。然后利用DAG的一些神奇的性质求解一些常见的问题。

核心代码如下:

void tarjan(int node){
    vis[node]=1;dfn[node]=low[node]=++dfs_clock;
    stack[++top]=node;
    for(int i=LINK[node];i;i=e[i].next)
        if(!dfn[e[i].y]){
            tarjan(e[i].y);
            low[node]=min(low[node],low[e[i].y]);
        }else if(vis[e[i].y])    low[node]=min(low[node],dfn[e[i].y]);
	if(dfn[node]==low[node]){
		group_num++;
		int tmp;
		do{
			tmp=stack[top--];
			vis[tmp]=0;
			group[tmp]=group_num;
		}while(tmp!=node);
	}
}

每次执行完后,$group$值相同的就是强连通分量里的。同时$group_{num}$也代表这里有几个强连通分量。

需要注意的是,这个只适用于有向图的缩点建图。如果以这个为模板特判父亲然后妄想把无向图缩成一棵树就是大错特错,至于有向图的缩点请参考下面的点双联通分量

无向图求割点/割边

求割点和割边其实无差,如果一个点存在一条边为割边,那么这个点一定是割点.

相应的,对于点$node$的儿子$son$,如果$dfn[node] \leq low[son] $,那么$edge_{(node,son)}$就是一条割边,而$node$也就是相应的割点。

特殊的,如果$node$为$root$,且只有一个儿子,也满足上述条件,但显然$node$不是割点,所有需要特判。

void tarjan(int node,int father){
    vis[node]=1;dfn[node]=low[node]=++dfs_clock;
    for(int i=LINK[node];i;i=e[i].next)if(e[i].y!=father){
        if(!dfn[e[i].y]){
            outdu[node]++;
            tarjan(e[i].y,node);
            cmin(low[node],low[e[i].y]);
            if(low[e[i].y]>=dfn[node])OK[node]=1;
        }else if(vis[e[i].y]) cmin(low[node],dfn[e[i].y]);
    }
    if(outdu[node]==1&&node==1)OK[node]=0;
}

无向图求点双联通分量

这一块相对来说比较复杂,可以去做一道题。什么是点双联通分量?直白点说就是从一个点到另一个点的一个"圈"。

之前说到了用求强连通分量的方法不能把一个图缩成树来搞,可以参考一下这张图。

如果只用那种方法,这整张图都会被缩成一个点,但是显然这个图应该是两个点双联通分量。

可以注意到,连接着两个点双联通分量的点是一个割点,因此可以借用之前思路来求解求解点双联通分量。

void tarjan(int node){
    dfn[node]=low[node]=++dfs_clock;
    stack[++top]=node;int son=0;
    Auto(i,node)if(!dfn[e[i].y]){
        tarjan(e[i].y);
        cmin(low[node],low[e[i].y]);
        if(low[e[i].y]>=dfn[node]){
            int tmp;group_num++;
            do{
                tmp=stack[top--];
                group[group_num].pb(tmp);
            }while(tmp!=e[i].y);
            group[group_num].pb(node);
        }
    }else cmin(low[node],dfn[e[i].y]);
}

乍一看好像和求强连通分量没什么区别,确实。这个只是把我们称之为缩点的过程移到了循环里。

在建树的时候也跟第一个的构建新图不是很一样。对于每个点双联通分量,新建一个点,这个点向点双联通分量里的每个点连边。最终一定能构成一棵树,而这个树上任意两点之间的路径上所包含的点(除虚点)都是在原图上必经的点。

Tarjan三把刀的更多相关文章

  1. 我的runloop学习笔记

    前言:公司项目终于忙的差不多了,最近比较闲,想起叶大说过的iOS面试三把刀,GCD.runtime.runloop,runtime之前已经总结过了,GCD在另一篇博客里也做了一些小总结,今天准备把ru ...

  2. Solr学习(2) Solr4.2.0+IK Analyzer 2012

    Solr学习(二) Solr4.2.0+IK Analyzer 2012 开场白: 本章简单讲述如何在solr中配置著名的 IK Analyzer 分词器. 本章建立在 Solr学习(一)  基础上进 ...

  3. 自学JQuery Mobile的几个例子

    JQuery Mobile是一个用于构建移动Web应用程序的框架,适用于主流的移动设备(智能手机.平板电脑),该框架利用了HTML5和CSS3技术减少了额外的脚本文件的编写.具体JQuery Mobi ...

  4. android开发 RecyclerView 列表布局

    创建一个一行的自定义布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns ...

  5. hihoCoder 1185 连通性·三(Tarjan缩点+暴力DFS)

    #1185 : 连通性·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 暑假到了!!小Hi和小Ho为了体验生活,来到了住在大草原的约翰家.今天一大早,约翰因为有事要出 ...

  6. 《程序员代码面试指南》第三章 二叉树问题 Tarjan算法与并查集解决二叉树节点间最近公共祖先的批量查询问题

    题目待续.... Tarjan算法与并查集解决二叉树节点间最近公共祖先的批量查询问题 java代码

  7. Tarjan在图论中的应用(三)——用Tarjan来求解2-SAT

    前言 \(2-SAT\)的解法不止一种(例如暴搜?),但最高效的应该还是\(Tarjan\). 说来其实我早就写过用\(Tarjan\)求解\(2-SAT\)的题目了(就是这道题:[2019.8.14 ...

  8. Newnode's NOI(P?)模拟赛 第三题 (主席树优化建图 + tarjan)

    题目/题解戳这里 这道题题目保证a,b,ca,b,ca,b,c各是一个排列-mdzz考场上想到正解但是没看到是排列,相等的情况想了半天-然后写了暴力60分走人- 由于两两间关系一定,那么就是一个竞赛图 ...

  9. OO第三单元——基于JML的社交网络总结

    OO第三单元--基于JML的社交网络总结 一.JML知识梳理 1)JML的语言基础以及基本语法 JML是用于java程序进行规格化设计的一种表示语言,是一种行为接口规格语言.其为严格的程序设计提供了一 ...

随机推荐

  1. 为什么数据库有时候不能定位阻塞(Blocker)源头的SQL语句

    在SQL Server数据库或OACLE数据库当中,通常一个会话持有某个资源的锁,而另一个会话在请求这个资源,就会出现阻塞(blocking).这是DBA经常会遇到的情况.当出现SQL语句的阻塞时,很 ...

  2. [已解决]从微软合作伙伴资源和MSDN下载系统和软件Microsoft download Manager无效

    有个itellyou,更新了所有MSDN的软件包.如果自己有微软的注册账户,还是从微软官网下载比较好.而且对自己账户里的系统和itellyou里的做了对比.发现SHA1码不相同,估计官方分配的序列号也 ...

  3. 读《高性能javascript》笔记(一)

    第一章加载与执行:1,js脚本会阻塞页面渲染,<script>尽可能放到<body>标签的底部2, 合并脚本,页面中的<script>标签越少:HTTP请求带来的额 ...

  4. C库函数使用与总结之时间函数

    1. localtime(取得当地目前时间和日期) [头文件]#include <time.h> [函数原型]struct tm *localtime(const time_t * tim ...

  5. [HTML]输入框被限制输入某些类型数据

    ENTER键可以让光标移到下一个输入框 <input onkeydown="if(event.keyCode==13)event.keyCode=9" > 只能是中文& ...

  6. Neutron 理解 (2): 使用 Open vSwitch + VLAN 组网 [Netruon Open vSwitch + VLAN Virutal Network]

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  7. Neutron 理解(10):虚拟专用网(VPN)虚拟化 [How Neutron implements VPN Virtualization]

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  8. 第27章 java I/O输入输出流

    java I/O输入输出流 1.编码问题 import java.io.UnsupportedEncodingException; /** * java涉及的编码 */ public class En ...

  9. Winform listview控件、 容器控件

    1.常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示:只有在Details视图该属性才有意义. (2) GridLines:设置行和列之间是否显示网格 ...

  10. 用于部署war并重启Tomcat的脚本

    只需要定义两个变量, 一个是目标tomcat实例的目录, 另一个是war包的名称 # Please define the absolute path of tomcat instance THIS_T ...