有向图的强连通分量(SCC)
来源:互联网 发布:漓江学院 知乎 编辑:程序博客网 时间:2024/06/05 08:08
在有向图G 中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。
如果有向图G 的每两个顶点都强连通,称G 是一个强连通图。
非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达,{5},{6}也分别是两个强连通分量。
直接根据定义,用双向遍历取交际的方法求强连通分量,时间复杂度为O(N^2+M)。更好的方法是Kosaraju算法或者Tarjan算法。
两者的时间复杂度都是O(N+M)。
Tarjan 算法:
Tarjan 算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
定义DFN(u)为节点u 搜索的次序编号(时间戳),Low(u)为u 或u 的子树能够追溯到的最早的栈中节点的次序号。由定义可以得出,当 DFN(u)=Low(u)时,以u 为根的搜索子树上所有节点是一个强连通分量。
算法步骤:
1.当首次搜索到点u时dfn[u]=low[n]=time
2.每当搜索到一个点,把该点压入栈顶
3.当u和v有边相连时,如果v不在栈中(树枝边),dfs(v),并且low[u]=min{low(u),low(v)},如果v在栈中(前向边/后向边),此时low[u]=min{low[u],dfn[v]}
4.当dfn[u]=low[u]时,将它以及在它之上的元素弹出栈,此时,弹出栈的结点构成一个强连通分量
5.继续搜索,知道图被遍历完毕。
由于在这个过程中每个点只被访问一次,每条边也只被访问一次,所以Tarjan算法的时间复杂度是O(n+m)
Tarjan模板:
#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <stack>#define max(a,b) (a>b?a:b)#define min(a,b) (a>b?b:a)using namespace std;const int N=1001;int time=1;int low[N],dfn[N];bool instack[N];stack<int>st;struct LIST{ int v; LIST *next;};LIST *head[N]={NULL};void tarjan(int v)/*tarjan求强连通分支*/{ dfn[v]=low[v]=time++;/*标记点v的DFS遍历序号*/ st.push(v);/*将点v入栈*/ instack[v]=true;/*标记点v已经在栈中*/ for(LIST *p=head[v];p!=NULL;p=p->next)/*遍历V能直接到达的点*/ { if(!dfn[p->v])/*如果v的邻接点没有入过栈*/ { tarjan(p->v); low[v]=min(low[v],low[p->v]);/*如果v能直接到达的这个点没在栈中,v的最早祖先为他们中的较小值*/ } else if(instack[p->v])/*如果在栈中*/ low[v]=min(low[v],dfn[p->v]);/*如果在栈中,则v的最早祖先是他的序号和那个点的序号较小的*/ } if(dfn[v]==low[v])/*如果dfn[v]和low[v]相等,则说明v点是其所属强连通分支DFS遍历起点,这个强连通分支所有点都在v点之上*/ { cout<<"{ "; do { v=st.top(); st.pop(); instack[v]=false; cout<<v<<' '; }while(dfn[v]!=low[v]); cout<<"}"<<endl; }}int main(){ int i,j,n,m; cin>>n; while(!st.empty()) st.pop(); memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); for(i=0;i<=n;i++) head[i]=NULL; for(i=1;i<=n;i++) { cin>>m;//i的邻接点数量 //输入每个邻接点编号 LIST *rear=head[i]; for(j=0;j<m;j++)/*创建邻接表*/ { if(!j) { rear=new LIST; head[i]=rear; } else { rear->next=new LIST; rear=rear->next; } rear->next=NULL; cin>>rear->v; } } for(i=1;i<=n;i++) if(!dfn[i])/*如果i没有入过栈*/ tarjan(i); return 0;}
例题:
hdu 1269
算是Tarjan 的模板题
题解传送门:http://blog.csdn.net/ezcufst/article/details/47017459
- 【有向图强连通分量(SCC)】
- 有向图的强连通分量 SCC tarjin算法
- 有向图的强连通分量(SCC)
- 求解有向图的强连通分量的SCC问题---POJ 2186 Popular Cows
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- 有向图的强连通分量
- Tarjan算法求SCC(有向图强连通分量)
- Git的Patch功能
- ios开发之MVC模式理解
- Snail—UI学习之动画Animations
- OC基础回顾(七)Foundation Kit 框架
- C# TreeView的使用以及节点的拖动
- 有向图的强连通分量(SCC)
- XMPP的基础知识
- Objective-C学习笔记(四)——OC实现最简单的数学运算
- 42. Trapping Rain Water
- Spring(二)编码剖析Spring对JavaBean的管理
- Android API Guides 阅读笔记(1)----Application Fundamentals
- 关于java基础--日期类与日历类Calendar详解测试
- nyoj17单调递增最长子序列
- java容易忽略的基础知识