强连通图(Tarjan算法)

概念

强连通:如果a点和b点可互达,则称a和b强连通
强连通图:如果一个图中的任意两个点之间都是强连通,则称该图为强连通图
强连通分量:一个图的子图是一个强连通图,则称该子图就是原图的一个强连通分量

Tarjan算法

需要存储的信息:首先肯定要有一个邻接表/邻接矩阵来存储边的信息,一个DFN数组存储该点的访问时间戳(即第几个被访问),还要有一个low数组储存在一个强连通分量中根节点的的时间戳,还要有一个栈存储当前可访问到的点,以及一个vis数组存储一个元素是否在栈中
思路:利用DFS,从一个点出发,延着有向边不断遍历,如果一个点已经在栈中,则说明这两个点强连通,就把这个强连通图的根结点设为时间戳小的那个
代码:

vector<int> mp[MAXN];
stack<int> sta;
int low[MAXN], DFN[MAXN], vis[MAXN], 
int index = 0;

void tarjan(int v)
{
	low[v] = DFN[v] = ++index;
	sta.push(v);
	vis[v] = 1;
	for(int i = 0; i < mp[v].size(); i++)
	{
		if(!DFN[mp[v][i]])
		{
			tarjan(mp[v][i]);
			low[v] = min(low[v], low[mp[v][i]]);
		}
		else if(vis[mp[v][i]])
		{
			low[v] = min(low[v], low[mp[v][i]]);
		}
	}

	if (low[v] == DFN[v])
	{
		while(true)
		{
			int x = sta.top();
			sta.pop();
			vis[x] = 0;
			index--;
			printf("%d\n", x);
			if(x == v)
			{
				break;
			}
		}
	}
}

调用:

void solve(int n)
{
	memset(DFN, 0, sizeof(DFN));
	memset(low, 0, sizeof(low));
	for(int i = 1; i <= n; i++)
	{
		if(!DFN[i])
		{
			tarjan(i);
		}
	}
}

你可能感兴趣的:(ACM算法模版)