暑期总结-Tarjan算法

来源:互联网 发布:网络天天分红投资公司 编辑:程序博客网 时间:2024/05/21 06:36

强连通分量是指有向图G里顶点间能互相到达的子图

即在这个子图中每个顶点直接或间接地连接。

Tarjan算法:规定一个数组dfn[i]记录第一次访问到i的时间,并将i入栈,然后low[i]记录该点所在的强连通子图所在搜索子树的根节点的Dfn值,又搜索子树中越靠前的dfn值越小,所以要尽量找小的dfn值。

伪代码:

tarjan(u){    DFN[u]=Low[u]=++Index                // 为节点u设定次序编号和Low初值    Stack.push(u)                        // 将节点u压入栈中    for each (u, v) in E                 // 枚举每一条边        if (v is not visted)             // 如果节点v未被访问过            tarjan(v)                    // 继续向下找            Low[u] = min(Low[u], Low[v])        else if (v in S)                 // 如果节点v还在栈内            Low[u] = min(Low[u], DFN[v])    if (DFN[u] == Low[u])                // 如果节点u是强连通分量的根        repeat             v = S.pop                    // 将v退栈,为该强连通分量中一个顶点            print v        until (u== v)}

注意:由于一张图中可能有多个强连通分量,所以需要做多次tarjan操作。

tarjan求得之后,可以将同一强连通分量看作一个点,那么就可以得到一张有向无环图(DGA图),在有些题目中可以用到。

求强连通分量代码:

#include <cstdio>int n,m,first[10010],arraynum,strack[10010],top,in[10010],flag[10010];int dfn[10010],low[10010],time,ans[10010],cont,js[10010];struct ppp{int go,next;}array[100010];int min(int x,int y){if(x<y) return x; return y;}void tarjon(int u){dfn[u]=low[u]=++time;strack[++top]=u; in[u]=1; flag[u]=1;for(int i=first[u];i!=0;i=array[i].next){int v=array[i].go;if(flag[v]==0){tarjon(v);low[u]=min(low[u],low[v]);}else if(in[v]==1){low[u]=min(low[u],dfn[v]);}}int v;if(dfn[u]==low[u]){cont++;do{v=strack[top--];in[v]=0;ans[v]=cont;//注意存储连通分量的方式 js[cont]++;//}while(u!=v);}}int main(){scanf("%d%d",&n,&m);int i;for(i=1;i<=m;i++){int a,b; scanf("%d%d",&a,&b);array[++arraynum].go=b+1;array[arraynum].next=first[a+1];first[a+1]=arraynum;}for(i=1;i<=n;i++){if(flag[i]==0) tarjon(i);//做多次tarjan操作 }int max=0,t;for(i=1;i<=n;i++){if(js[i]>max){max=js[i]; t=i;}}for(i=1;i<=n;i++){if(ans[i]==t) printf("%d ",i-1);//点的编号从0~N; }}



0 0
原创粉丝点击