tarjan算法不是很懂先mark一下。
三种tarjan算法(上)
- 求强连通分量
- 求无向图的割和桥
- 最近公共祖先
求强连通分量
基本概念:
- 时间戳 :DFN[i]是指结点i被遍历的时间。
- Low[i] :是指在搜索树中,结点i和其子孙可以访问到的最早的祖先,Low[i] = Min(DFN[i], DFN[j], Low[k])其中j是i的祖先(我们把子孙连到祖先的边叫后向边),k是i 的子女。
- 结点的颜色:color[i]是用于标示结点i的状态:白色指还没到搜索到,灰色正在被搜索,黑色处理完毕。在实际操作中用-1,0,1分别代表白色、灰色、黑色。
tarjan算法的步骤:
- 先把所有的结点的颜色都初始化白色,并把栈清空。
- 找到一个白色的结点i(即结点的颜色为白色)
- 给结点一个时间戳,把结点圧入栈中,并把结点标记为灰色。令Low[i] = DFN[i]
- 遍历结点i 的每条边(i,j)。若color[j]是白色,就对结点i重复2~5步骤。并令Low[i] = min(Low[j],low[i]).如果color[j]是灰色,令Low[i] = min(Low[i],DFN[j])。如果是黑色不做任何处理。
- 把结点的颜色改为黑色,如果Low[i] = DFN[i],就把从栈顶到结点i间的元素弹出
- 重复步骤2,至到没有白色顶点
下面是算法的一个模板:
- <pre name="code" class="cpp">#include <math.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- //从顶点0开始
- // 要用的话要初始化:调用Adj.initial 和 tarjan.initial
- //要解决问题用调用tarjan.solve
- //对tarjan.initial要传入的参数是图边集Adj,和顶点个数n
- const int maxn = 11000;
- //顶点的规模
- const int maxm = 210000;
- //边的规模,如果是无向图要记得乘以2
- const int GRAY = 0;
- const int WHITE =-1;
- const int BLACK = 1;
- typedef struct Edge{
- int s;
- int e;
- int next;
- }Edge;
- typedef struct Adj{
- int edge_sum;
- int head[maxn];
- Edge edge[maxm];
- void initial(){
- edge_sum = 0;
- memset(head,-1,sizeof(head));
- }
- void add_edge(int a, int b){
- edge[edge_sum].s = a;
- edge[edge_sum].e = b;
- edge[edge_sum].next = head[a];
- head[a] = edge_sum++;
- }
- }Adj;
- typedef struct Tanjan{
- int n;
- int *head;
- Adj *adj;
- Edge *edge;
- int cnt;
- int top;
- int cur;
- int dfn[maxn];
- int low[maxn];
- int color[maxn];
- int stack[maxn];
- int belong[maxn];
- void initial(Adj *_adj,int _n){
- n = _n;
- adj = _adj;
- head = (*adj).head;
- edge = (*adj).edge;
- }
- void solve(){
- memset(dfn,-1,sizeof(dfn));
- memset(color,WHITE,sizeof(color));
- top = cnt = cur = 0;
- for(int i = 0; i < n; i++)
- if(color[i] == WHITE)//找到一个白色的顶点,就开始处理
- tarjan(i);
- }
- inline int min(int a, int b){
- if(a < b) return a;
- else return b;
- }
- void tarjan(int i){
- int j = head[i];
- color[i] = GRAY;//标记为灰色
- stack[top++] = i;//把结点圧入栈顶
- dfn[i] = low[i] = ++cur;//给结点一个时间戳,并给Low初始化
- while(j != -1){
- int u = edge[j].e;
- if (dfn[u] == WHITE){
- tarjan(u);
- low[i] = min(low[i],low[u]);
- //更新low
- }else if (color[u] == GRAY)
- low[i] = min(low[i],dfn[u]);
- //一条后向边
- j = edge[j].next;
- }
- color[i] = BLACK;
- if(low[i] == dfn[i]){
- do{
- j = stack[--top];
- belong[j] = cnt;
- }while(i != j);
- ++cnt;
- }
- }
- }Tarjan;
- Adj adj;
- Tarjan tj;</pre><br>
- <br>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
tarjan算法的简单证明:
#define M 5010//题目中可能的最大点数
int STACK[M],top=0;//Tarjan算法中的栈
bool InStack[M];//检查是否在栈中
int DFN[M];//深度优先搜索访问次序int Low[M];//能追溯到的最早的次序
int ComponentNumber=0;//有向图强连通分量个数
int Index=0;//索引号
vector<int> Edge[M];//邻接表表示
vector<int> Component[M];//获得强连通分量结果
int InComponent[M];//记录每个点在第几号强连通分量里
int ComponentDegree[M];//记录每个强连通分量的度void Tarjan(int i)
{int j;DFN[i]=Low[i]=Index++;InStack[i]=true;STACK[++top]=i;for (int e=0;e<Edge[i].size();e++){j=Edge[i][e];if (DFN[j]==-1){Tarjan(j);Low[i]=min(Low[i],Low[j]);}elseif (InStack[j]) Low[i]=min(Low[i],DFN[j]);}if (DFN[i]==Low[i]){ComponentNumber++;do{j=STACK[top--];InStack[j]=false;Component[ComponentNumber].push_back(j);InComponent[j]=ComponentNumber;}while (j!=i);}
}
tarjan算法不是很懂先mark一下。相关推荐
- 【转】BYV--有向图强连通分量的Tarjan算法
转自beyond the void 的博客: https://www.byvoid.com/zhs/blog/scc-tarjan 注:红色为标注部分 [有向图强连通分量] 在有向图G中,如果两个顶点 ...
- 有向图强连通分量tarjan算法
转自:http://www.byvoid.com/blog/scc-tarjan/ http://blog.csdn.net/geniusluzh/article/details/6601514 在有 ...
- byvoid 神牛的tarjan算法讲解!
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通 (strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图 .非强连通图有向图 ...
- 有向图强连通分量的Tarjan算法——转自BYVoid
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- [转载] 有向图强连通分量的Tarjan算法 ——byvoid
[有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极 ...
- 有向图强连通分量的Tarjan算法
有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大 ...
- 有向图强连通分量之Tarjan算法
出处https://www.byvoid.com/zhs/blog/scc-tarjan [有向图强连通分量] 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly con ...
- 强连通分量及缩点tarjan算法解析
http://blog.csdn.net/justlovetao/article/details/6673602 有向图强连通分量的Tarjan算法 [有向图强连通分量] 在有向图G中,如果两个顶点间 ...
- 寻找强连通分量的Tarjan算法
有向图的强连通分量 在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.非强连通图有向图的极大 ...
最新文章
- MPLS是如何工作?MPLS的完整指南和常见问题解答
- 硬件产品研发,除了电子元器件成本,还有什么成本?
- [ZJOI2014] 璀璨光华(bfs建图 + dfs搜索)
- 【渝粤题库】国家开放大学2021春2626药事管理与法规题目
- 光遇安卓服务器维修,《光遇》渠道服更换手机解决办法
- 计算机组装与维护推荐教材,计算机组装与维护(全国高等专科教育计算机类规划教材)...
- 服务器上如何修改伪静态,服务器如何设置伪静态和301重定向
- 操作系统—进程的状态与状态的转换
- 简单记录 Part1.1
- [需求管理-9]:需求规格说明书SRS
- Unity 导航网格的使用
- nmap 扫描服务器开放了哪些端口
- EEGLAB 脑电数据处理与分析
- 凌恩生物明星产品:一文读懂细胞器基因组!
- SQL中数据类型转换
- 解决redis Could not get a resource since the pool is exhausted 问题
- Vue入门笔记Day 8
- java 变量 英文_Java中的字符类型变量无论是中文,英文还是数字,都是占4字节。...
- linux双系统如何选择顺序,Ubuntu和Windows双系统选择开机顺序
- java 房贷计算器代码_用JAVA编程一个房贷计算器