一、强连通

在有向图G中,如果两个顶点间至少存在一条互相可达路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。

这里写图片描述
如上图,如果两个点成强联通,那么显然在树中就会存在一个环,图中L-M-J-L和A-L-M-B-A成环所以组成的强联通分量。

二、targan算法

由于强连通分量中的点相互连通,所以如果用dfs遍历到这个分量时,一定会回溯到已经遍历过的同属于这个分量的点

如图所示,图的一个强连通分量会在dfs时会形成以A为根节点的子树,我们只需要找出这个子树,并能够取出这个子树,也即利用Targan算法,Targan算法基于DFS和栈来实现,每次遍历到一个点时就把该点压栈。

首先建立两个数组DFN[] 和 LOW[], DFN[]用来记录点被遍历到的时候的时间,(会再定义一个全局变量做计时器),作用在于区分点,以及识别根,因为,当DFS走到强连通分量中的第一个点时,这个点的DFN[]一定是最小的,如图中的A。

LOW[]记录每个点能够回溯到的点的最小的DFN值,如B能够回溯到A,他的LOW实际就是A的DFN

 

LOW值一定小于DFN

scc[]表示某个点在缩点后的强连通分量坐标
sccnum表示缩点后强连通分量的个数
numinscc[]表示缩点后每个强连通分量中点的个数
一旦点的DFN不等于其LOW时,意味着他可以回溯到更早的点,所以这个点一定不是根节点。

当一个点的DFN==LOW时,这个点就是根,就将栈中该点及之上的所有点出栈,他们同属于一个强连通分量
(原文:https://blog.csdn.net/qq_36428237/article/details/80640401 )
代码


vector<int> G[10010];
stack<int> s;
int low[10010];
int dfn[10010];
int time = 0;
int scc[10010];
int sccnum = 0;
int visit[10010];
int numinscc[10010];
int outdegree[10010];
void Targan(int u)
{
    low[u] = dfn[u] = ++time;
    visit[u] = 1;
    s.push(u);
 
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if(visit[v] == 0)
        {
            Targan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(visit[v] == 1&&scc[v] == 0)
            low[u] = min(low[u],dfn[v]);
    }
 
 
    int m;
    if(dfn[u] == low[u])
    {
        sccnum++;
        do
        {
            m = s.top();
            s.pop();
            scc[m] = sccnum;
            numinscc[sccnum]++;
        }while(m!=u);
    }
 
 
}
//需要计算出入度为0的点的话可以遍历每个点以及其儿子,判断是否于同一分量,再按照分量进行判断出入度
//另,一个图中需要添加max(in_0,out_0)条边以成为连通图

发表评论

邮箱地址不会被公开。 必填项已用*标注