有向图的强连通分支:在有向图G中,如果任意两个不同的顶点相互可达,则称该图是强连通的。有向图G的极大连通子图为G的强连通分支;
图中每个节点只属于一个强连通分支;
有关DAG(有向无环图)的一些定理性质:(有时需要特殊考虑只有一个节点的时候)
1、DAG中唯一出度为0的点,一定可以由任意点出发可达。因为无环,所以从任何点出发,必然终止于一个出度为0的点;
2、DAG中,所有入度不为0的点一定可以由某个入度为0的点出发可达。因为无环,所以从入度不为0的点往回走,必然终止于一个入度为0的点;
3、在DAG中加max(n,m)(其中n为入度为0的点数,m为出度为0的点数)条边,能使DAG变成强连通的;即为每个入度为0的点添加入边,为每个出度为0的点添加出边;
有向图的强连通分支问题常通过求强连通分量,缩点,转化为DAG问题;
求解有向图强连通分量的Korasaju算法:(G的转置T和G具有相同的强连通分量)
1、深度优先遍历G,按照dfs完成的先后顺序将节点记录下来;
2、深度优先遍历G的转置图T,按照1中节点结束时间从大到小选择为遍历的起点,遍历T。遍历过程中给节点分类,每找到一个新的起点,分类就加1;
3、第二步产生的标记值相同的节点构成深度优先深林中的一棵树,即一个强连通分量;
算法时间复杂度为(V+E)
注意:Korasaju算法求强连通分量得到标记点,根据原图G对其缩点建DAG后,标记编号最大的点对应的一定是DAG中的出度为0的点,编号最小的点一定是DAG中的一个入度为0的点(特殊考虑原图本身就是双连通的,即缩点后只有一个点)
poj2186 Korasaju算法;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<string>
#define ll long long
#define MAX 10010
#define INF INT_MAX
#define eps 1e-8
using namespace std;
struct Edge{
int from,to;
};
vector<Edge>edges;
vector<int> G[MAX],T[MAX],A[MAX];
vector<int>S;
int n;
void init(){
for (int i=0; i<= n; i++){
G[i].clear();
T[i].clear();
A[i].clear();
}
S.clear();
edges.clear();
}
int vis[MAX],sccno[MAX],scc_cnt;
void dfs1(int u){
if (vis[u]) return;
vis[u]