图论算法(6)(更新版) --- Tarjan算法求强连通分量

之前Tarjan算法求强连通分量博文中,代码实现用到了固定大小数组,扩展起来似乎并不是很方便,在java里这样来实现本身就是不太妥当的,所以下面给出一个更新版本的代码实现:

package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

public class TarjanSCC<NodeType> {
	int index;
	Map<NodeType, LinkedList<NodeType>> dag;
	Map<NodeType, Integer> indexMap;
	Map<NodeType, Integer> lowLinkMap;
	Stack<NodeType> stack;
	List<List<NodeType>> result;

	public TarjanSCC(Map<NodeType, LinkedList<NodeType>> dag) {
		this.index = 0;
		this.dag = dag;
		this.indexMap = new HashMap<NodeType, Integer>();
		this.lowLinkMap = new HashMap<NodeType, Integer>();
		this.result = new ArrayList<List<NodeType>>();
	}

	public List<List<NodeType>> tarjan() {
		this.index = 0;
		stack = new Stack<NodeType>();
		List<List<NodeType>> result = new ArrayList<List<NodeType>>();
		for (NodeType v : this.dag.keySet()) {
			if (indexMap.get(v) == null) {
				result.addAll(this.strongConnect(v));
			}
		}
		return result;
	}

	public List<NodeType> getSuccessors(NodeType v,Map<NodeType, LinkedList<NodeType>> dag) {
		List<NodeType> successors = new ArrayList<NodeType>();
		Set<NodeType> set = dag.keySet();
		Iterator<NodeType> it = set.iterator();
		while (it.hasNext()) {
			NodeType node = it.next();
			if (node.equals(v)) {
				successors.addAll(dag.get(node));
				break;
			}
		}
		return successors;
	}

	public List<List<NodeType>> strongConnect(NodeType v) {
		indexMap.put(v, index);
		lowLinkMap.put(v, index);
		index++;
		stack.push(v);
		for (NodeType w : getSuccessors(v, dag)) {
			if (indexMap.get(w) == null) {
				strongConnect(w);
				lowLinkMap.put(v, Math.min(lowLinkMap.get(v), lowLinkMap.get(w)));
			} else if (stack.contains(w)) {
				lowLinkMap.put(v, Math.min(lowLinkMap.get(v), indexMap.get(w)));
			}
		}
		if (lowLinkMap.get(v).equals(indexMap.get(v))) {
			List<NodeType> sccList = new ArrayList<NodeType>();
			while (true) {
				NodeType w = stack.pop();
				sccList.add(w);
				if (w.equals(v)) {
					break;
				}
			}
			if (sccList.size() > 1) {
				result.add(sccList);
			}
		}
		return result;
	}
}
时间: 2024-10-22 13:13:35

图论算法(6)(更新版) --- Tarjan算法求强连通分量的相关文章

HDU1269迷宫城堡(裸Tarjan有向图求强连通分量个数)

迷宫城堡Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 13833    Accepted Submission(s): 6174 Problem Description 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房

转 tarjan算法求强连通分量

无意中想起图的强连通分量来,之前也一直想写所以今天决定来填这个坑.PS:由于本人比较懒,之前做过一个讲解的PPT,不过那是好遥远之前,年代已久早已失传,所以本文里的图来自网络.以后周末都用来填坑也挺好. ------------------------------分割线----------------------------------------- 在有向图G中,如果两个顶点间至少存在一条路径,那么这两个顶点就是强连通(strongly connected). 如果有向图G的每两个顶点都强连通

poj1236 Network of Schools ,求强连通分量(Tarjan算法),缩点

题目链接: 点击打开链接 题意: 给定一个有向图,求: 1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点 2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点 顶点数<= 100 求完强连通分量后,缩点,计算每个点的入度,出度. 第一问的答案就是入度为零的点的个数, 第二问就是max(n,m) // 入度为零的个数为n, 出度为零的个数为m. //kuangbin巨巨分析很棒! #include<cstdio> #include<cstring>

Tarjan 算法求 LCA / Tarjan 算法求强连通分量

[时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarjan算法_LCA - A_Bo的博客 - CSDN博客 Tarjan离线算法求最近公共祖先(LCA) - 初学者 - CSDN博客 最近公共祖先(LCA) - riteme.site Fuzhou University OnlineJudge P3379 [模板]最近公共祖先(LCA) - 洛谷 |

算法描述》关于tarjan算法两三事

关于tarjan,在下觉得这个算法从本质上是一种暴力求强连通分量的方法,但事实上这也是最有效的求强连通分量的方法之一,它对于处理各种强连通分量中奇怪问题,都可以直接转化,所以比较通用和常见. 什么是tarjan 粗略的描述一下(详细描述在百度里很详细) 首先每个点都有时间戳和最小子树戳. 时间戳的定义是这个点进行递归的时间,每新递归一次就增加,所以每个点的时间戳都不一样,最小子树戳的定义是当前点的子树上节点中(包括它自己)时间戳的最小值. 它的基本方法是先把任意一个没有tarjan过的点加入栈,

CCF 高速公路 tarjan求强连通分量

问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的计划.看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能.如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对. 国王想知道,在大臣们给他的计划中,有多少个便利城市对. 输入

poj 2186 tarjan求强连通分量

蕾姐讲过的例题..玩了两天后才想起来做 貌似省赛之后确实变得好懒了...再努力两天就可以去北京玩了! 顺便借这个题记录一下求强连通分量的算法 1 只需要一次dfs 依靠stack来实现的tarjan算法 每次走到一个点 马上把它压入栈中 每次对与这个点相连的点处理完毕 判断是否low[u]==dfn[u] 若是 开始退栈 直到栈顶元素等于u才退出(当栈顶元素等于u也需要pop) 每次一起退栈的点属于同一个强连通分量 储存图可以用链式前向星也可以用邻接矩阵更可以用vector 蕾姐说不会超时 我信

POJ-3180 The Cow Prom(tarjan求强连通分量)

题目链接:http://poj.org/problem?id=3180 题目大意:求一个有向图的强连通分量 算法:求强连通分量首选tarjan算法 这里简单说一下tarjan的思路 时间戳是什么:在搜索时访问的最早时间 维护dfn[u]表示u的时间戳 low[u]表示u点所能回到的最早的祖先的时间戳 开一个栈,把搜索的点入栈.搜索时遇到已经搜过的点,取low[u]和dfn[v]的最小值,回溯时取low[u]和low[v]的最小值(标记上传)传到dfn[u]<=low[u]时表示已经回溯到最上面的

Tarjan求强连通分量、求桥和割点模板

Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using namespace std; const int maxn = 1e3 + 10; const int maxm = 330000 + 10; struct EDGE{ int v, nxt; }Edge[maxm]; int Head[maxn], cnt; int DFN[maxn], LOW[maxn],