Tarjan

发布时间 2024-01-01 16:04:03作者: q(x)

强连通分量

相关的定义
  1. 强连通:我们称一个图是强连通的,当且仅当这个图的任意两个点相互可达。
  2. 强连通图:一张强连通的图。
  3. 强连通子图:一个强连通的子图。
  4. 强连通分量 \(\mathcal{(} \text{scc} \mathcal{)}\):极大的两联同子图。
求解强连通分量 \(tarjan\) 算法

对于一个点,维护两个量:\(\text{low,dfn}\).

整个过程是在 dfs 中进行的,会生成一颗 dfs 生成树,所以下面的讲述中可能会牵扯到一些树的定义;
我们会制作栈,记录访问的节点,当找到一个 \(\text{scc}\) 的时候将栈弹出元素进行处理。

其中 \(\text{dfn}\) 表示这个点的 \(\text{dfs}\) 访问顺序,\(\text{low}\) 表示这个点最早可以访问到的点,形式化地,这个点可以到达的深度最小的点。

一些显著的特征:当 \(\text{low=dfn}\) 的时候可以找到一个 \(\text{scc}\),顺着栈找就行了。

更加详细地,\(\text{low}\) 小于等于 \(\text{dfn}\) ,因为这个点至少可以访问到自己。而 \(\text{low}\) 可以顺着 \(\text{dfs}\) 迭代。

典型应用:缩点

可以将处于相同强连通分量的点缩成一点,让原图 \(\mathcal{G}\) 缩成一个 \(DAG:\) \(\mathcal{T}\) 这样做方便于处理一些问题。

code
namespace Graph{
	std::vector<int> G[N],T[N];
	int col[N],stack[N],dfn[N],low[N],val[N],a[N];
	int f[N];
	int top,tot;
	int n,m,Cnt;
	std::bitset<N> vis;
	void Init_Input(void){
		n=R(),m=R();
		for(int i=1;i<=n;++i)
			a[i]=R();
		for(int i=1;i<=m;++i){
			int ai=R(),aj=R();
			G[ai].add(aj);
		}
	}
	void Tarjan(int u){
		dfn[u]=low[u]=++tot;
		stack[++top]=u;
		vis[u]=true;
		for(int v:G[u]){
			if(!dfn[v]) Tarjan(v),low[u]=std::min(low[v],low[u]);
			else if(vis[v])  low[u]=std::min(low[u],dfn[v]);
		} if(dfn[u]==low[u]){
			++Cnt;
			while(stack[top]!=u){
				col[stack[top]]=Cnt;
				val[Cnt]+=a[stack[top]];
				vis[stack[top]]=0;
				top--;
			}
			col[stack[top]]=Cnt;
			val[Cnt]+=a[stack[top]];
			vis[stack[top]]=0;
			top--;
		}
	}
	int ans=0;
	void Run(void){
		Init_Input();
		for(int i=1;i<=n;++i)
			if(!dfn[i]) Tarjan(i);
		for(int i=1;i<=n;++i){
			for(int v:G[i])
				if(col[i]!=col[v])
					T[col[i]].add(col[v]);
		}
		for(int i=Cnt;i;--i){
			f[i]+=val[i];
			ans=std::max(ans,f[i]);
			for(int v:T[i]) f[v]=std::max(f[v],f[i]);
		}
	}
	void Output(){ IO::W(ans);putchar('\n'); }
}
int main(){ Graph::Run();Graph::Output(); }
例题:

\(\color{white}{P2746}\) 缩点计算入度,处理处理推倒推倒就好了。

\(\color{white}{P2812}\) 上面这道题的加强版,一种思路。

\(\color{white}{CF999E}\) 还是计算入度,推倒推倒思考思考就好了。

\(\color{white}{P3627}\) 缩点 \(dp\) 的基础题。在 \(\text{DAG}\) 上面考虑转移,也可以在缩点 \(\text{DAG}\) 上面求最短路。