Tarjan算法---强联通分量
2014-08-19 11:37
281 查看
1、基础知识
在有向图G,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。
![](http://img.blog.csdn.net/20140819112344323?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWluZzEwMQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。栈中节点只有在其所属的强连通分量已经全部求出时,才会出栈。如果发现某节点u有边连到搜索树中栈里的节点v,则更新u的low
值为dfn[v](更新为low[v]也可以)。如果一个节点u已经DFS访问结束,而且此时其low值等于dfn值,则说明u可达的所有节点,都不能到达任何在u之前被DFS访问的节点 那么该节点u就是一个强连通分量在DFS搜索树中的根。此时将栈中所有节点弹出,包括u,就找到了一个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
Low(u)=MIN{ DFN(u), Low(v),(u,v)为树枝边,u为v的父节点,DFN(v),(u,v)为指向栈中节点的后向边(非横叉边)
}
在有向图G,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。 下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。
Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。栈中节点只有在其所属的强连通分量已经全部求出时,才会出栈。如果发现某节点u有边连到搜索树中栈里的节点v,则更新u的low
值为dfn[v](更新为low[v]也可以)。如果一个节点u已经DFS访问结束,而且此时其low值等于dfn值,则说明u可达的所有节点,都不能到达任何在u之前被DFS访问的节点 那么该节点u就是一个强连通分量在DFS搜索树中的根。此时将栈中所有节点弹出,包括u,就找到了一个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
Low(u)=MIN{ DFN(u), Low(v),(u,v)为树枝边,u为v的父节点,DFN(v),(u,v)为指向栈中节点的后向边(非横叉边)
}
[code]当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
2、参考代码
/* Tarjan算法:求一个有向图G=(V,E)里极大强连通分量。 强连通分量是指有向图G里顶点间能互相到达的子图。 如果一个强连通分量已经没有被其它强通分量完全包含,那这个强连通分量就是极大强连通分量*/ /*low[v]=dfn[v]时,栈里v以及v以上的顶点全部出栈,一个极大强连通分量*/ #include<stdio.h> #include<stdlib.h> #define MAXL 50 #define MIN(x,y) ((x) < (y) ? (x) : (y)) //结点定义 typedef struct edge_node{ int key; struct edge_node *next; }ENode; typedef struct{ char vertex; ENode *firstedge; }VNode; typedef VNode VList[MAXL]; typedef struct{ VList vlist; int n,e; }ALGraph; int instack[MAXL]; //用于标记是否在栈中 int vis[MAXL]; int dfn[MAXL],low[MAXL]; int depth; int ind[MAXL]={0}; int top; int stack[MAXL]; //【【【要用到】】】 int num_scc; int count_SCCele; int scc[MAXL]; ALGraph *ALG=(ALGraph *)malloc(sizeof(ALGraph)); //邻接表生成[有向图] void creat_ALGraph(ALGraph *ALG) { int i,j,k; char ch1,ch2; ENode *ep; scanf("%d,%d",&ALG->n,&ALG->e); for(i=0;i<ALG->n;i++) //顶点表 { getchar(); scanf("%c",&ALG->vlist[i].vertex); ALG->vlist[i].firstedge=NULL; } for(k=0;k<ALG->e;k++) //边表 { getchar(); scanf("%c,%c",&ch1,&ch2); for(i=0;ALG->vlist[i].vertex!=ch1;i++); for(j=0;ALG->vlist[j].vertex!=ch2;j++); ep=(ENode*)malloc(sizeof(ENode)); ep->key=j; ep->next=ALG->vlist[i].firstedge; ALG->vlist[i].firstedge=ep; } } //邻接表输出 void print_ALGraph(ALGraph *ALG) { int i; ENode *ptr=(ENode*)malloc(sizeof(ENode)); for(i=0;i<ALG->n;i++) { printf("%c",ALG->vlist[i].vertex); ptr=ALG->vlist[i].firstedge; while(ptr!=NULL) //不能用!ptr { printf("->%c",ALG->vlist[ptr->key].vertex); ptr=ptr->next; } printf("\n"); } } //计算初始化用于dfnlow()和bicon() void init_Tarjan(void) { depth=0; for(int i=0;i<ALG->n;i++) { instack[i]=0; dfn[i]=low[i]=-1; vis[i]=0; } top=0; //栈初始化 for(int j=0;j<ALG->n;j++) stack[j]=-1; num_scc=0; } void init_scc(void) //scc块初始化 { count_SCCele=0; for(int i=0;i<ALG->n;i++) scc[i]=-1; } void SCC_Tarjan(int u) { int son; ENode *ptr=(ENode *)malloc(sizeof(ENode)); dfn[u]=low[u]=depth++; //访问+访问标记+入栈+入栈标记+遍历 instack[u]=1; vis[u]=1; stack[top++]=u; ptr=ALG->vlist[u].firstedge; while(ptr!=NULL) { son=ptr->key; if(!vis[son]) { SCC_Tarjan(son); low[u]=MIN(low[u],low[son]); } else if(instack[son]) //在栈中 { low[u]=MIN(low[u],dfn[son]); } ptr=ptr->next; } if(dfn[u] == low[u]) //若此,以u为根的强连通分量 { num_scc++; init_scc(); do{ top--; scc[count_SCCele++]=stack[top]; instack[stack[top]]=0; }while(stack[top] != u); for(int cn=0;cn<count_SCCele;cn++) printf("%c ",ALG->vlist[scc[cn]].vertex); printf("\n"); } } int main(void) { creat_ALGraph(ALG); print_ALGraph(ALG); init_Tarjan(); for(int i=0;i<ALG->n;i++) //***可以处理不连通的图,如果连通只需要一次即可,即给定一个root,直接bridge_Tarjan(root,-1)*** if(!vis[i]) SCC_Tarjan(i); // SCC_Tarjan(2); //root可以自定义 printf("%d\n",num_scc); printf("%s %s %s\n","ver","dfn","low"); for(int l=0;l<ALG->n;l++) printf("%c: %3d %3d\n",ALG->vlist[l].vertex,dfn[l],low[l]); return 0; }
相关文章推荐
- POJ 2186 Popular Cows(强联通分量缩点+tarjan算法)
- 求有向图强联通分量--Tarjan算法
- Tarjan算法 (强联通分量 割点 割边)
- 强联通分量 缩点 tarjan算法
- 求解有向图的强联通分量--tarjan算法(tarjian求最小环模板)
- HDU 1269 迷宫城堡 (强联通分量,Tarjan算法)
- 强联通分量简讲(Tarjan算法)&&HDU 1269 迷宫城堡
- 强联通分量 Tarjan算法 模板
- 强联通分量tarjan算法(模板)
- 有向图的强联通分量 Tarjan算法模板
- 【POJ 1236 Network of Schools】强联通分量问题 Tarjan算法,缩点
- tarjan算法 求解强联通分量 POJ_2186_Popular Cows
- HDU1269 迷宫城堡 强联通分量Tarjan算法
- Tarjan算法---强联通分量
- 求强联通分量——Tarjan算法
- 有向图的强联通分量Tarjan算法模版(hdu1269)
- 强联通分量 Tarjan算法
- 求解强联通分量 tarjan算法
- Tarjian算法求强联通分量【STL_stack的运用】
- 【洛谷2661】信息传递 强联通分量