强连通分量

Kosaraju

基于两次dfs有向图强连通。 1.第一步:对原有的有向图G进行DFS,记录节点访问完的顺序,d[i],d[i]表示第i个访问完的结点是d[i] 1.第二部,选择具有最晚访问完的顶点,对反向图GT进行DFS,删除能够变力道的顶点,构成一个强连通分量。记录一下 3.如果还有顶点没有删除,继续第二部,否则算法结束。

# include <iostream>
using namespace std;
int st[10000];//可以用stl stack 代替 
int t = 0;//可以用stl stack 代替 
struct edge{ 
	int t,next;
}edges[100000],edges2[100000];
int head[10000];
int head2[10000];
int top2;
int top;
int visited[10000];
void add1(int f,int t){
	edges[++top].next = head[f];
	edges[top].t = t;
	head[f] = top;
}
void add2(int f,int t){
	edges[++top2].next = head2[f];
	edges[top2].t = t;
	head2[f] = top2;
}
void dfs(int s){
	visited[s] = true;
	for(int i = head[s];i!=0;i = edges[i].next){
		if(!visited[edges[i].t]){
			dfs(edges[i].t);
		}
	}
	st[++t] = s;
}
void dfs2(int s){
	visited[visited[edges2[s].t] = true;
	for(int i = head[s];i!=0;i = edges2[i].next){
		dfs2(edges[2].t);//可以在此记录强连通分量的顶点 
	}
}
int kosaraju(){
	int sum = 0;
	for(int i = 1;i<=n;i++){
		if(!visited[i]){
			dfs(i);
		}
	}
	memset(visited,false,sizeof(visited));
	for(int i = n;i>=1;i--){//选择具有最晚访问完的顶点,对反图进行dfs 
		if(!visited[st[i]]){
			sum++;
			dfs2(st[i]);
		}
	}
	//强连通分量数 
	return sum;
}

tarjan

Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。 再Tarjan算法中,有如下定义。 DFN[ i ] : 在DFS中该节点被搜索的次序(时间戳) LOW[ i ] : 为i或i的子树能够追溯到的最早的栈中节点的次序号 当DFN[i]==LOW[i]时,为i或i的子树可以构成一个强连通分量。 详细解析见详细的tarjan讲解 代码:

# include <iostream>
using namespace std;
struct edge{
	int t,next;
}edges[10000];
int head[10000];
int top;
void add(int f,int t){
	edges[++top].next = head[f];
	edges[top].t = t;
	head[f] = top;
}
bool visited[1000];//某个节点是否在栈中
int dfn[1000];
int low[1000];
int dfn_sum;
int stack[10000];
int stop;
int color[10000];//哪个点染什么色,颜色一样的点属于同一个强连通分量 
int color_val = 0;
inline int minn(int x,int y){return x>y?y:x;}
void tarjan(int x){
	dfn[x] = ++dfn_sum;
	low[x] = dfn_sum;
	visited[x] = true;
	stack[++stop] = x;
	for(int i = head[x];i!=0;i = edges[i].next){
		int v = edges[i].t;
		if(dfn[v]==0){
			tarjan(v);
			low[x] = minn(low[x],low[v]);
		}else if(visited[v]){
			low[x] = minn(low[x],dfn[v]);//是回溯到的节点靠前,还是本来已经找到的节点靠前 
		}
	}
	if(dfn[x]==low[x]){
		visited[x] = false;
		color[x] = ++color_val;
		while(stack[top]!=x){
			color[stack[top]] = color_val;
			visited[stack[top--]] = false;
		}
		top--;//点x已经在栈中,并且已经找到了一个强连通分量,上一个在栈中的点x出栈 
	}
} 

缩点