强连通缩点

强连通分量+缩点+拓扑排序 模板

(强连通建立新图)(tarjan找强连通分量)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
typedef long long ll;
const constexpr int maxN = 1e6+3;
typedef int int_vec[maxN];
struct dag_helper
{
	int n,t;
	dag_helper(int _n=-1,int _t=0):n(_n),t(_t) {}
	bool operator<(const dag_helper& d) const
	{
		return t > d.t;
	}
};
int V,E;
int_vec head,to,next,dfn,low,belong,S,end;
int edge_count,time,scc_count,scc_edge_count,top,time_2;
dag_helper helper[maxN];
void init()
{
	std::fill_n(head,maxN,-1);
	std::fill_n(to,maxN,-1);
	std::fill_n(next,maxN,-1);
	std::fill_n(dfn,maxN,0);
	std::fill_n(low,maxN,0);
	std::fill_n(belong,maxN,-1);
	std::fill_n(end,maxN,0);
	scc_edge_count = 0;
	edge_count = 0;
	time = 0;
	scc_count = 0;
	top = -1;
	time_2 = 0;
}
void add(int u,int v)
{
	to[edge_count] = v;
	next[edge_count] = head[u];
	head[u] = edge_count++;
}
void scc_add(int u,int v)
{
	u += V;
	v += V;
	to[edge_count+scc_edge_count] = v;
	next[edge_count+scc_edge_count] = head[u];
	head[edge_count+scc_edge_count] = edge_count+scc_edge_count;
	++scc_edge_count;
}
void targan(int x)
{
	if (dfn[x]) return;
	dfn[x] = low[x] = ++time;
	S[++top] = x;
	for (int i=head[x];i>=0;i=next[i])
	{
		int y = to[i];
		if (!dfn[y])
		{
			targan(y);
			if (low[x] > low[y]) low[x] = low[y];
		}
		else if ((belong[y] == -1) and (low[x] > dfn[y])) low[x] = dfn[y];
	}
	if (dfn[x] == low[x])
	{
		while (true)
		{
			belong[S[top]] = scc_count;
			if (S[top--] == x) break;
		}
		++scc_count;
	}
}
void shrink()
{
	for (int i=0;i<V;++i)
	for (int j=head[i];j>=0;j=next[j])
	{
		int t = to[j];
		if (belong[i] != belong[t]) scc_add(belong[i],belong[t]);
	}
}
void dfs(int x)
{
	for (int i=head[x];i>=0;i=next[i])
	{
		int y = to[i];
		if (!end[y]) dfs(y);
	}
	end[x] = ++time_2;
}
void dag()
{
	for (int i=0;i<scc_count;++i) dfs(V+i);
	for (int i=0;i<scc_count;++i)
	{
		helper[i].t = end[V+i];
		helper[i].n = i;
	}
	std::sort(helper,helper+scc_count);
}
void doit()
{
	for (int i=0;i<V;++i) targan(i);
	shrink();
	dag();
}
int main()
{
	V = 8;
	init();
	add(0,1);
	add(1,2);
	add(1,4);
	add(1,5);
	add(2,3);
	add(2,6);
	add(3,2);
	add(3,7);
	add(4,0);
	add(4,5);
	add(5,6);
	add(6,5);
	add(6,7);
	add(7,7);
	doit();
	for (int i=0;i<V;++i) std::printf("%d\n",belong[i]);
	for (int i=0;i<scc_count;++i) std::printf("%d %d\n",helper[i].n,helper[i].t);
	std::printf("FIN\n");
}

注:

1.S为stack,可以用std::stack替代

2.helper最后的排序即为对应强连通分量的拓扑序(注意编号)

3.每个节点i属于belong[i]分量

4.节点编号、边编号从0开始,强联通节点编号从V开始,强联通边编号从E开始(初始时E == edge_count)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值