首页 > 其他分享 >tarjan

tarjan

时间:2024-03-13 10:35:30浏览次数:25  
标签:tarjan int 结点 ++ dfn tj low

缩点

有向图缩点(把一个强连通分量看成一个点),用于优化。

  • 树枝边:DFS 时经过的边,即 DFS 搜索树上的边
  • 反祖边:也叫回边或后向边,与 DFS 方向相反,从某个结点指
    向其某个祖先的边
  • 横叉边:从某个结点指向搜索树中另一子树中的某结点的边,它
    主要是在搜索的时候遇到了一个已经访问过的结点,但是这个结
    点并不是当前结点的祖先时形成的
  • 前向边:与 DFS 方向一致,从某个结点指向其某个子孙的边,
    它是在搜索的时候遇到子树中的结点的时候形成的

对于每个点维护两个值 \((dfn,low)\) ,\(dfn\) 是 \(dfs\) 序,\(low\) 表示这条路走到头能回到祖宗的最小值(或叶子),对于一个点 \(u\) ,如果他的 \(low[u]\) 等于 \(dfn[u]\) ,说明 向下 \(dfs\) 时还能回到 \(u\) ,则中间这部分构成一个强连通分量。
如图,先 \(dfs\) 到 \(e\) ,\(dfn[e]==low[e]\),发现一个强连通分量,\(e\) 出栈,回溯到 \(b\) ,第二个强连通分量,将 \(b,c,d\) 出栈。
缩完点变成有向无环图(DAG),可以跑最短路,可以dp,很方便。

code
void tj(int s)
{
	dfn[s]=low[s]=++num;
	v[s]=1; st.push(s);
	for(int i=head[s];i;i=e[i].nxt)
	{
		int to=e[i].to;
		if(!dfn[to])
		{
			tj(to);
			low[s]=min(low[s],low[to]);
		}
		else if(v[to]) low[s]=min(low[s],dfn[to]);
	}
	if(dfn[s]==low[s])
	{
		int now;
		t++;
		do
		{
			now=st.top(); st.pop();
			v[now]=0; bl[now]=t;
			sz[t]++;
		} while(s!=now);
	}
}
int main()
{
	………… 
	memset(head,0,sizeof(head)); tot=0;
	for(int i=1;i<=m;i++)
		if(bl[x[i]]!=bl[y[i]])
		add(bl[x[i]],bl[y[i]]);
	………… 
}

割点

无向图求割点,就是删掉后能把图隔成几个部分的点,思路和缩点类似,如果 \(dfn[u]<=low[v]\) ,说明 \(u\) 以下有一个连通块,且 \(u\) 下面的连通块和 \(u\) 上面的没有联系,所以此时 \(u\) 为割点。
如图 \(B,E,K\) 为割点。
(注意,根节点如果只有一个儿子,他不是割点。)

code
void tj(int s)
{
	dfn[s]=low[s]=++num;
	int son=0;
	for(int i=head[s];i;i=e[i].nxt)
	{
		int to=e[i].to;
		if(!dfn[to])
		{
			tj(to);
			low[s]=min(low[s],low[to]);
			if(dfn[s]<=low[to])
			{
				son++;
				if(s!=root || son>1)
				{
					if(!ans[s]) cnt++;
					ans[s]=1;
				}
			}
		}
		else	
			low[s]=min(low[s],dfn[to]);
	}
}

割边

无向图求割边,定义和割点差不多了,如 \(dfn[u]<low[v]\) 则 \((u,v)\) 为割边(注意不能 \(=\) ),上图割边有 \(A-B\)以及 \(E-K\) 和 \(K-L\) ,因为是无向图,建边时都建成了正向反向两条边,所以要判一下正向反向的两条边,避免原路走回去。

code
void tj(int s,int fa)
{
	dfn[s]=low[s]=++num;
	for(int i=head[s];i;i=e[i].nxt)
	{
		int to=e[i].to;
		if(to==fa) continue;
		if(!dfn[to])
		{
			tj(to,s);
			low[s]=min(low[s],low[to]);
			if(dfn[s]<low[to]) ans++;
		}
		else low[s]=min(low[s],dfn[to]);
	}
}

标签:tarjan,int,结点,++,dfn,tj,low
From: https://www.cnblogs.com/ppllxx/p/18070058

相关文章

  • Tarjan算法求SCC,缩点
    Tanjan算法可以在O(n+m)的时间内求出强连通分量,常数小,是个非常优秀的算法。算法实现过程:dfn[x]表示x的dfs生成树上的编号,代表着时间戳,low[x]表示从x结点出发,能够访问到最早的时间戳。<1>进入u时,盖上时间戳,结点入栈。<2>枚举该点的结点的时候,分为三种情况:(1)如果该点v没有访......
  • tarjan板子整理
    缩点stack<int>q;voidtarjan(intu){ pre[u]=low[u]=++cnt; q.push(u); vis[u]=1; for(inti=head[u];i;i=nxt[i]) { inty=to[i]; if(!pre[y]) { tarjan(y); low[u]=min(low[u],low[y]); } elseif(vis[y]) { low[u]=min(low[u],pre[y]);......
  • Tarjan 全家桶
    部分定义摘自Alex_Wei的博客,如有侵权,请联系笔者删除。割点在无向图中,删去后使得连通分量数增加的结点称为割点。孤立点不是割点。非根节点\(u\)为割点当且仅当dfs树上存在一条树边\(u\rightarrowv\)使得\(\operatorname{low}_v\geq\operatorname{dfn}_u\)。根节......
  • Tarjan 算法
    part1:离线求\(lca\)将走过的点且未回溯的标记为\(1\),已回溯的标记为\(2\),未访问标记为\(0\)把对于一点\(x\)的询问\(y\)存进相应的\(vector\),当回溯时判断如果询问的点标记为\(2\),则\(lca\)为询问的点\(y\)到根的路径上最早标记为\(1\)的点但直接找复杂度不对......
  • Dijkstra/Tarjan-关键边
    题目描述总统要回家,即从s走到t,会经过一些街道,每条街道都是单向的并且拥有权值。现在,为了让总统更好的回家,要对每一条街道进行操作:①如果该街道一定在最短路上,则输出“YES”。②如果该街道修理过后,该边所在的最短路可以取代原先的最短路,则输出“CANx”,x是修改该街道的最小花......
  • tarjan 全家桶
    无向图的tarjan求边双连通分量的个数以及每个边双连通分量的大小以及每个边双连通分量包含哪些点。bridge数组表示一条边是不是桥。#include<bits/stdc++.h>usingnamespacestd;constintN=5e5+10,M=2e6+10;structedge{ intx,y,pre;}a[M*2];intalen,last[N];voidin......
  • Tarjan
    Tarjan前置知识搜索树&搜索森林\(在一张连通图中,所有的节点以及发生递归的边共同构成一棵搜索树。如果这张图不连通,则构成搜索森林。\)\(\color{green}树边:\)\(dfs经过的边,dfs搜索树の边\)\(\color{yellow}返祖边:\)\(可以理解为返回去の边\)\(\color{red}横叉边:\)\(df......
  • Tarjan 算法(超详细!!)
    Tarjan算法前言说来惭愧,这个模板仅是绿的算法至今我才学会。我还记得去年CSP2023坐大巴路上拿着书背Tarjan的模板。虽然那年没有考连通分量类似的题目。现在做题遇到了Tarjan,那么,重学,开写!另,要想学好此算法的第一件事——膜拜Tarjan爷爷。Tarjan算法到底是什么其......
  • Tarjan的学习笔记
    \(Tarjan\)的学习笔记一,\(tarjan\)概述:(1)定义:$~~~~~~~~$$tarjan$是基于深度优先搜索的一种算法,求解图的连通性等问题,巧妙地利用了对图进行深搜时产生的搜索树上的边。(2)\(tarjan\)中的几种边:\(~~~~~~~~\)树边:父亲与孩子的边。\(~~~~~~~~\)前向边:祖先到孩子的边(树边属于特......
  • hszxoj 矿场搭建 [tarjan]
    hszxoj矿场搭建题目描述原题来自:HNOI2012煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道......