首页 > 其他分享 >【模板】Tarjan

【模板】Tarjan

时间:2022-11-23 09:11:19浏览次数:99  
标签:Tarjan int top dfn low 500010 col 模板

posted on 2022-07-07 20:52:49 | under 模板 | source

0x00 有向图缩点

现有一有向图 \(G=(V,E)\),称一个点集 \(E'\in E\) 为强连通分量,当且仅当 \(E'\) 的任意两点可以互相到达(围成一个环),求出所有极大强连通分量即 \(\tt SCC\)。

使用 Tarjan,我们将这个有向图看成一棵树,dfs 遍历,用 \(dfn_u\) 记录访问点 \(u\) 的时间戳。由于它是一个图,所以会有一些边返回到其它访问过的点(一定是祖先,这是 dfs 生成树的性质),称作返祖边。

记录 \(low_u\),它表示点 \(u\) 通过 dfs 树和最多一次返祖边能到达的最小的 \(dfn\)。如果 \(low_u=dfn_u\),我们断言点 \(u\) 的整一棵子树是一个 \(SCC\),因为从点 \(u\) 出发能回到点 \(u\),就是一个环。但是,\(low_u\) 不能经过已经缩完点的点,这样两个 \(SCC\) 就套在一起了,可以合成一个大的 \(SCC\) 了。

点击查看代码
int dfn[1010],low[1010],stk[1010],col[1010],cnt,top,tot;
void reset(){
	cnt=0;
	tot=0;
	memset(dfn,0,sizeof dfn);
	memset(col,0,sizeof col);
}
void tarjan(int u){
    low[stk[++top]=u]=dfn[u]=++cnt;
    for(int i=g.head[u];i;i=g.nxt[i]){
        int v=g[i].v;
        if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
        else if(!col[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        col[u]=++tot;
        while(stk[top]!=u) col[stk[top--]]=tot;
        top--;
    }
}

0x01 边双连通分量

在缩点的基础上,强制不让它走到父亲边即可。

点击查看代码
graph<500010,2000010> g;
int dfn[500010],low[500010],stk[500010],cnt,top,col[500010],dcc,siz[500010];
bool vis[2000010<<1];
void tarjan(int u){
	dfn[u]=low[stk[++top]=u]=++cnt;
	for(int i=g.head[u];i;i=g.nxt[i]){
		if(vis[i]||vis[i^1]) continue;
		int v=g[i].v;
		if(!dfn[v]) vis[i]=vis[i^1]=1,tarjan(v),low[u]=min(low[u],low[v]);
		else low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		col[u]=++dcc;
		do col[stk[top]]=dcc; while(stk[top--]!=u);
	}
}

0x02 无向图割点

与有向图缩点没有区别,在代码上。

但是,无向图割点的条件变为:\(low_v\geq dfn_u\),这样 \(v\) 这个儿子就走不到 \(u\),割掉 \(u\),\(v\) 就过不来了。

点击查看代码
int dfn[500010],low[500010],stk[500010],cnt,top,cut[500010];
void tarjan(int u){
	dfn[u]=low[stk[++top]=u]=++cnt,cut[u]=1;
	for(int i=g.head[u];i;i=g.nxt[i]){
		int v=g[i].v;
		if(!dfn[v]){
			tarjan(v),low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]) cut[u]++;
		}else low[u]=min(low[u],dfn[v]);
	}
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i),cut[i]--;
int ans=0;
for(int i=1;i<=n;i++) ans+=cut[i]>=2;
//cut[i] 表示割掉 i 点会剩下多少个连通块,割点就是 cut[i]>=2

标签:Tarjan,int,top,dfn,low,500010,col,模板
From: https://www.cnblogs.com/caijianhong/p/template-tarjan.html

相关文章

  • Java FreeMarker模板引擎注入深入分析
    0x01前言最近和 F1or 大师傅一起挖洞的时候发现一处某CMSSSTI的0day,之前自己在复现jpress的一些漏洞的时候也发现了SSTI这个洞杀伤力之大。今天来好好系统学习......
  • template模板初步介绍(11)
    template模板文本文件,嵌套有脚本(使用模板编程语言编写)借助模板生成真正的文件,Jinja2语言Jinja2是基于python的模板引擎,功能比较类似于于PHP的smarty,J2ee的Freemarker和......
  • Mat_类模板
    先来段代码感受一下MatC=(Mat_<double>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);MatD=(Mat_<double>(3,3)<<1,2,3,4,6,7,8,9,10);cout<<"C="<<......
  • 归并排序模板
    题目给定你一个长度为n的整数数列。请你使用归并排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式输入共两行,第--行包含整数n。第二行包含n个整......
  • GVIM使用及模板制作
    「教程」GVIM使用及模板制作原创2022-11-2209:26·​​明德扬FPGA科教​​GVIM是类似于记事本的代码编辑工具,但相比于记事本其输入效率更高,可以更好的提升工作效率。由于......
  • 手把手教你如何用界面组件DevExpress WPF应用一个模板主题
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专......
  • 随机数模板
    #ifndef_RANDOM_#define_RANDOM_#include<iostream>#include<ctime>#include<cstdlib>#include<algorithm>intrandom(intx){//生成一个0到x-1范围......
  • php中的模板模式
    概念 在模板模式(TemplatePattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。定义一个操作中的......
  • 站长素材免费简历模板爬取
    importrequestsimportosfromlxmlimportetreeif__name__=='__main__':#如果没有JianLi文件夹存在则创建文件夹ifnotos.path.exists('./JianLi'):......
  • P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并
    有一说一,雨天的尾巴我其实骂了很久。主要是题面之前一直没耐心读,然后后面在其他地方看到了形式化题意,就做掉了。其实感觉有很多题都比这玩意适合当板子,所以这个迟到的板子......