Tarjan 求强连通分量
2015-10-05 19:59
337 查看
首先介绍一下什么是(有向图)强连通分量——
在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通。如果有向图G的每两个顶点都强连通,则称G是一个强连通图。非强连通图有向图的极大强连通子图,成为强连通分量。
下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达,{5},{6}也分别是两个强连通分量。
tarjan算法是利用dfs依次遍历相连的点,每到达一个点,就记录下到达该点的次序(即程序中的dfn数组),与一个待更新的最早次序,每个点的最早次序是指与其同处一个环的点的最小次序(例如:依次到达点2、4、6、7、3,其到达次序分别为1、2、3、4、5,若此五点在一个环中,则其最小次序均为1。这个在程序中用low数组维护),之后将这个点压入一个栈(在后来同处一个环的会一起弹出)。
显然同处一个环的除第一个被遍历的点的low是小于dfn的,所以说当将遇到dfn与low相等的点就将与它上面的点(还记得那个存在感极低的栈吗?)一起弹出,弹出的一系列的点就在一个环里。如果一个点不与其他点构成环,显然会只弹出这一单点。
更新low时注意要分类讨论一下,其他就没什么了。
下面是个输出同处一个环的点的程序。
#include<bits/stdc++.h> using namespace std; const int maxn=5005; int N,M; int stac[maxn],top=0;//Tarjan算法中的栈 bool instac[maxn];//检查是否在栈中 int dfn[maxn];//深度优先搜索访问次序 int low[maxn];//能追溯到的最早的次序 int tot=0;//有向图强连通分量个数 int index=0;//索引号 vector<int>to[maxn]; vector<int> kin[maxn];//获得强连通分量结果 int inkin[maxn];//记录每个点在第几号强连通分量里 inline void tarjan(int x){ dfn[x]=low[x]=index++; stac[++top]=x; instac[x]=true; for(int i=0;i<to[x].size();i++){ int y=to[x][i]; if(dfn[y]==-1){ tarjan(y); low[x]=min(low[x],low[y]); } else if(instac[y]!=0){ low[x]=min(low[x],dfn[y]); } } if(dfn[x]==low[x]){ tot++; int y; do{ y=stac[top--]; instac[y]=false; kin[tot].push_back(y); inkin[y]=tot; }while(y!=x); } } int main(){ scanf("%d%d",&N,&M); for(int i=1;i<=M;i++){ int u,v; scanf("%d%d",&u,&v); to[u].push_back(v); } memset(dfn,-1,sizeof(dfn)); for(int i=1;i<=N;i++){ if(dfn[i]==-1) tarjan(i); } for(int i=1;i<=N;i++){//输出分组 cout<<inkin[i]<<endl; } return 0; }
相关文章推荐
- GIT的使用
- 罗列系统中的所有字体
- Android 自定义圆形头像
- C与CUDA混合编程的配置问题
- 对象——创建对象
- C与CUDA混合编程的配置问题
- HDU1256画8
- Codeforces Round #323 (Div. 2)B. Robot's Task
- hdu5122 K.Bro Sorting
- orecle virtual box geneymotion无法开启问题
- 四则运算
- Android任务流调度 - Init
- iOS编程--------UIImagePickerController
- HDU 4810 Wall Painting(组合数学)
- cocos3——8.实现初学者指南
- [转]Fragment跳转至Activity或者Fragment
- IM6Q yocto开发平台搭建,学习FREESCALE官方手册笔记
- CComboBox控件的使用 1
- HTML5移动Web开发(四)——移动设计
- POJ 1511 Invitation Cards 最短路SPFA