tarjan[模板]

storms11發表於2024-11-27

強連通分量(有向圖)

void tarjan(int x)
{
	dfn[x]=low[x]=++cnt;
	stac[++top]=x;
	vis[x]=1;
	for(int i=hd[x];i;i=nxt[i])
	{
		int y=go[i];
		if(!dfn[y])//樹邊
		{tarjan(y);low[x]=min(low[x],low[y]);}
		else if(vis[y])low[x]=min(low[x],dfn[y]);//在棧中(判橫叉邊)
	}
	if(low[x]==dfn[x])//出不去
	{
	    col_cnt++;
	    while(stac[top+1]!=x){
	    	c[stac[top]]=col_cnt;
	    	vis[stac[top]]=0;
	    	ve[col_cnt].push_back(stac[top]);
	    	top--;
		}
	}
}

邊雙連通分量(無向圖)

void tarjan(int u,int fa)
{
	dfn[u]=low[u]=++cnt;
	stac[++top]=u;
	int son=0;
	for(int i=hd[u];i;i=nxt[i])
	{
		int v=go[i];
		if(!dfn[v])
		{
			son++;
			tarjan(v,i);
			low[u]=min(low[v],low[u]);
		}
		else if(i!=(fa^1)) low[u]=min(low[u],dfn[v]);//可以透過重邊走向父親
	}
	if(low[u]==dfn[u])
	{
		++col;
		while(stac[top+1]!=u)
		{	
			ans[col].push_back(stac[top--]);
		}	
	}
	return ;
}

點雙連通分量(無向圖)

void tarjan(int u,int fa)
{
	dfn[u]=low[u]=++cnt;
	stac[++top]=u;
	int son=0;
	for(int i=hd[u];i;i=nxt[i])
	{
		int v=go[i];
		if(!dfn[v])
		{
			son++;
			tarjan(v,u);
			low[u]=min(low[v],low[u]);
			if(low[v]>=dfn[u])
			{
				++col;
				while(stac[top+1]!=v)
				{	
					ans[col].push_back(stac[top--]);
				}	
				ans[col].push_back(u);//因為一個割點可能屬於多個點雙,所以不能出棧
			}
		}
		else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
	if(fa==0&&son==0)ans[++col].push_back(u);//特判獨立點
	return ;
}

相關文章