Strongly connected components of directed graphs

Posted by Cenron on Thu, 23 Dec 2021 06:37:00 +0100

B3609 [graph theory and algebraic structure 701] strongly connected components

Some concepts:

  1. If any two nodes in a directed graph x , y x,y x. Y, existence x x x to y y Path and of y y y y to x x The path of x is called a strongly connected graph;
  2. The maximal strongly connected subgraph of a directed graph is called a strongly connected component.

In the above, a strongly connected subgraph G ′ = ( V ′ , E ′ ) ( V ⊆ V , E ′ ⊆ E ) G'=(V',E')(V\subseteq V,E'\subseteq E) G ′ = (V ′, e ′) (V ⊆ V,E ′⊆ E) is maximal if and only if there is no inclusion G ′ G' Larger subgraphs of G ' G ′ ′ = ( V ′ ′ , E ′ ′ ) G''=(V'',E'') G ′′ = (V ′′, E ′′) satisfied V ′ ⊆ V ′ ′ ⊆ V , E ′ ⊆ E ′ ′ ⊆ E V'\subseteq V''\subseteq V,E'\subseteq E''\subseteq E V′⊆V′′⊆V,E′⊆E′′⊆E. Obviously, a ring must be a strongly connected graph, so our idea is to find all the points that can form a ring with a point.

As the URL in this article, the strongly connected component is abbreviated as SCC(Strongly Connected Component) \text{SCC(Strongly Connected Component)} SCC(Strongly Connected Component).

seek SCC \text{SCC} SCC can use Tarjan, Kosaraju or Garbow algorithm. This paper uses Tarjan algorithm.

definition:

  • ( int ⁡ \operatorname{int} int) T i m e Time Time: current timestamp;
  • ( int ⁡ \operatorname{int} int) t o t tot tot: SCC \text{SCC} Number of SCC;
  • ( int ⁡ \operatorname{int} int) d f n ( u ) dfn(u) dfn(u): point u u dfs order of u;
  • ( int ⁡ \operatorname{int} int) l o w ( u ) low(u) low(u): of the following nodes d f n dfn Minimum value of dfn: v ∈ s u b t r e e ( u ) v\in subtree(u) v∈subtree(u)( u u Subtree of u) and from v v v starting from a node that can be reached by an edge not on the search tree (non tree edge);
  • ( int ⁡ \operatorname{int} int) c ( u ) c(u) c(u): record point u u Where u is located SCC \text{SCC} SCC;
  • ( stack ⁡ \operatorname{stack} stack< int ⁡ \operatorname{int} int>) s t a sta sta: a stack;
  • ( bool ⁡ \operatorname{bool} bool) i n s ( u ) ins(u) ins(u): point u u Is u in s t a sta sta;
  • ( vector ⁡ \operatorname{vector} vector< int ⁡ \operatorname{int} int>) s c c ( i ) scc(i) scc(i): record No i i i SCC \text{SCC} All nodes in SCC.

The Tarjan algorithm is implemented using dfs:

  1. record d f n , l o w dfn,low dfn,low;
  2. Stack the current node;
  3. to update l o w low low:
    1. d f n ( v ) = 0 dfn(v)=0 dfn(v)=0: description v v v yes u u u's immediate son, v v v can reach u u u can be reached. Recurse down first, and then use it directly l o w ( v ) low(v) low(v) to update l o w ( u ) low(u) low(u);
    2. i n s ( v ) = t r u e ins(v)=true ins(v)=true: description v v v yes u u The ancestors of u and u u u can be reached by a non tree edge v v v. It can be used by definition d f n ( v ) dfn(v) dfn(v) to update l o w ( u ) low(u) low(u).
  4. After the update, if d f n ( u ) = l o w ( u ) dfn(u)=low(u) dfn(u)=low(u), indicating from u u u set out and finally returned u u u. That is, it constitutes a ring, which meets the requirements SCC \text{SCC} SCC. take t o t ← t o t + 1 tot\gets tot+1 Tot ← tot+1, while constantly bouncing the stack until it hits u u u. Then all the pop-up nodes are in the s u b t r e e ( u ) subtree(u) In subtree(u); Record it on page t o t tot tot SCC \text{SCC} In SCC; Finally, add it s c c ( t o t ) scc(tot) scc(tot).

Special requirements for the topic:

First line output 1 1 Strong connected component of point 1, output in the second line 2 2 If the strongly connected component of point 2 has been output, it will be output instead 3 3 The strongly connected component of point 3, and so on.

Open one( bool ⁡ \operatorname{bool} bool) v i s vis The vis array records each SCC \text{SCC} Whether SCC has been output.

Each strongly connected component is output according to the node number and size

sort ⁡ \operatorname{sort} sort once.

Code \text{Code} Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <stack>
#include <vector>
#define re register
using namespace std;

inline int read()
{
	re int x = 0, f = 0;
	re char c = getchar();
	while (c < '0' || c > '9')
	{
		f |= c == '-';
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		x = (x << 3) + (x << 1) + (c ^ '0');
		c = getchar();
	}
	return f ? -x : x;
}

inline void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9)
	{
		write(x / 10);
	}
	putchar(x % 10 ^ '0');
}

inline int min2(int x, int y)
{
	return x < y ? x : y;
}
//-----------------------------------------------------------
const int MAXN = 1e4 + 5;
const int MAXM = 1e5 + 5;

int cnt, Time, tot;
int head[MAXN], dfn[MAXN], low[MAXN], c[MAXN];
bool ins[MAXN], vis[MAXN];
stack<int> sta;
vector<int> scc[MAXN];

struct edge
{
	int to, nxt;
}e[MAXM];

void add(int u, int v)
{
	e[++cnt] = edge{v, head[u]};
	head[u] = cnt;
}

void tarjan(int u)
{
	dfn[u] = low[u] = ++Time; //initialization
	sta.push(u); //Enter the stack
	ins[u] = true; //sign
	for (re int i = head[u]; i; i = e[i].nxt)
	{
		int v = e[i].to; //to update
		if (!dfn[v])
		{
			tarjan(v);
			low[u] = min2(low[u], low[v]);
		}
		else if (ins[v])
		{
			low[u] = min2(low[u], dfn[v]);
		}
	}
	if (dfn[u] == low[u]) //Form a ring
	{
		tot++;
		int v = 0;
		while (u != v)
		{
			v = sta.top(); //Bomb stack
			sta.pop();
			ins[v] = false; //Unmark
			c[v] = tot;
			scc[tot].push_back(v); //Record answers
		}
	}
}

int main()
{
	int n = read(), m = read();
	for (re int i = 1; i <= m; i++)
	{
		int u = read(), v = read();
		add(u, v);
	}
	for (re int i = 1; i <= n; i++)
	{
		if (!dfn[i]) //Prevent disconnection
		{
			tarjan(i);
		}
	}
	write(tot);
	putchar('\n');
	for (re int i = 1; i <= n; i++)
	{
		int x = c[i];
		if (vis[x])
		{
			continue;
		}
		vis[x] = true; //Output already
		sort(scc[x].begin(), scc[x].end());
		for (re int i = 0; i < scc[x].size(); i++)
		{
			write(scc[x][i]);
			putchar(' ');
		}
		putchar('\n');
	}
	return 0;
}

Topics: Graph Theory