有向图4----有向图强连通性分析Kosaraju算法

强连通性:顶点v和w是互相可达的

有向图强连通:任意两个顶点都是强连通的

强连通分量:有向图中相互连通的顶点组成的最大子集

强连通分量--Kosaraju算法

给定一张有向图G,计算其反向图GR

将反向图进行顶点排序,取得逆后序顺序

按照GR逆后序顺序进行dfs搜索,在构造函数中同一个dfs递归调用中访问到的顶点属于同一个强连通分量

给定有向图G

                                              

求出反向图GR

        //有向图反转
	public Digraph reverse(){
		Digraph R = new Digraph(V);
		for(int v=0; v<V; v++){
			for(int w : adj[v]){
				R.addEdge(w, v);
			}	
		}
		return R;
	}

         

对于反向图进行顶点排序  https://blog.csdn.net/u014106644/article/details/90444801

             //对g的反向图进行顶点排序
		DepthFirstOrder order = new DepthFirstOrder(g.reverse());

按照GR逆后序顺序进行dfs搜索,在构造函数中同一递归调用访问的顶点属于同一强连通分量

public class KosarajuSCC {
	
	private boolean[] marked;
	private int[] id;
	private int count;
	
	public KosarajuSCC(Digraph g){
		marked = new boolean[g.V()];
		id = new int[g.V()];
		//对g的反向图进行顶点排序
		DepthFirstOrder order = new DepthFirstOrder(g.reverse());
		//对逆后序进行dfs 在同一个dfs递归调用中出现的顶点属于同一强连通分量
		for(int s : order.reversePost()){
			if(!marked[s]){
				dfs(g, s);
				count++;
			}
		}
	}

	private void dfs(Digraph g, int s) {
		marked[s] = true;
		id[s] = count;
		System.out.println("s " + s + " " + count);
		for(int v : g.adj(s)){
			if(!marked[v]){
				dfs(g, v);
			}
		}
	}
	
	public boolean stronglyConnected(int v, int w){
		return id[v] == id[w];
	}
	
	public int id(int v){
		return id[v];
	}
	
	public int count(){
		return this.count;
	}
	
	public static void main(String[] args) {
		Digraph g = GraphUtils.getDiGraphPointG3().getG();
		System.out.println(g.toString());
		KosarajuSCC scc = new KosarajuSCC(g);
		System.out.println(Arrays.toString(scc.id));
	}
}

最终结果:

[1, 0, 1, 1, 1, 1, 3, 4, 4, 2, 2, 2, 2]

          

Kosaraju算法证明

dfs路径搜索的特点:

如果存在路径s-->v,则首先dfs(s)开始----dfs(v)开始----dfs(v)结束----dfs(s)结束

1.每个和s强连通的顶点v都会在构造函数调用的dfs(G,s)被访问到

s,v强连通说明s-->v  v-->s  用反证法证明:
假定v没有再dfs(G,s)中访问到,由于s-->v,则必定v在之前已经被访问过;

又因为v-->s,如果v之前访问过则s也必定访问过,因此dfs(G,s)不会调用,即假设错误;

即每个和s强连通的顶点v都会在构造函数调用的dfs(G,s)被访问到

2.构造函数dfs(G,s)中所到达的任意顶点v必定与s是强连通的
由于dfs(G,s)访问到v则必定存在s-->v  只需要证明在G中有v-->s即可;
要证明G中有v-->s,只需要证明在GR中有s-->v
在GR中进行dfs,如果dfs(G,v)在dfs(G,s)之前结束,则说明在GR中存在路径s-->v,有两种情况:
dfs(G,v)在dfs(G,s)调用之前调用,在dfs(G,s)调用之前结束    不可能,因为在G中有s-->v,则GR中有v-->s,即如果dfs(G,v)开始调用,则必定会在递归中调用dfs(G,s),因此不可能在dfs(G,s)调用之前结束;

dfs(G,v)在dfs(G,s)调用之后调用,在dfs(G,s)结束之前结束,该情况说明含有路径s-->v

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python 中可以使用深度优先搜索 (DFS) 和拓扑排序 (Topological Sorting) 两种算法来查找有向图中的环路。 1. DFS 算法: 在 DFS 中,我们遍历整个,并且记录每个点的访问状态。当我们遍历到一个已经被访问过的点时,意味着我们找到了一个环路。 以下是一个基于 DFS有向图环路查找算法的 Python 代码: ```python def has_cycle(graph): visited = set() for node in graph: if node not in visited: if dfs(graph, node, visited): return True return False def dfs(graph, node, visited): visited.add(node) for neighbor in graph[node]: if neighbor not in visited: if dfs(graph, neighbor, visited): return True else: return True visited.remove(node) return False ``` 2. 拓扑排序算法: 拓扑排序是一种对有向无环 (DAG) 进行排序的算法。如果有向图中存在环路,则无法进行拓扑排序。 以下是一个基于拓扑排序的有向图环路查找算法的 Python 代码: ```python def has_cycle(graph): in_degree = {node: 0 for node in graph} for node in graph: for neighbor in graph[node]: in_degree[neighbor] += 1 queue = [node for node in graph if in_degree[node] == 0] visited = set(queue) while queue: node = queue.pop(0) for neighbor in graph[node]: in_degree[neighbor] -= 1 if in_degree[neighbor] == 0: queue.append(neighbor) visited.add(neighbor) return len(visited) != len(graph) ``` 以上就是 Python 中两种基本的有向图环路查找算法。如果您需要更加高效的实现,建议使用 Tarjan 算法Kosaraju 算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值