热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

stronglyConnectedComponents强联通分量求法kosarajutarjangabow并查集

1强联通分量解释SCC(stronglyConnectedComponents)对于G(v,e)的一个子图中,其任何两个顶点都存在一个path相互到达;2图的拓扑

1 强联通分量解释

SCC(stronglyConnectedComponents) 对于G(v, e)的一个子图中,其任何两个顶点都存在一个path相互到达;

2 图的拓扑排序

拓扑排序的核心思路还是利用深度优先搜索,排序的基本思想为深度优先搜索正好只会访问每个顶点一次,如果将dfs的参数顶点保存在一个数据结构中,遍历这个数据结构就能访问图中的所有顶点,而遍历的顺序取决于这个数据结构的性质以及是在递归调用之前还是递归调用之后保存。

  • 1 前序: 在递归调用之前将顶点加入队列 —- pre()方法
  • 2 后序: 在递归调用之后将顶点加入队列 —- post()方法
  • 3 逆后序: 在递归调用之后将顶点压入栈 —- reversePost()方法
    这里给出一个逆后序的例子:
    https://cdn.jsdelivr.net/gh/xychen5/blogImgs@main/imgs/强联通分量.77kjmz93ddc0.png
    其逆后序得到的一个栈为:(右侧为栈顶,代表最晚完成访问的节点) 6 4 2 5 3 1

逆后序获得代码:

public class DepthFirstOrder {private boolean[] marked;private Queue<Integer> pre; //所有顶点的前序排列private Queue<Integer> post; //所有顶点的后序排列private Stack<Integer> reversePost; //所有顶点的逆后序排列public DepthFirstOrder(Digraph G){pre &#61; new Queue<Integer>();post &#61; new Queue<Integer>();reversePost &#61; new Stack<Integer>();marked &#61; new boolean[G.V()];for(int v &#61;0;v<G.V();v&#43;&#43;)if(!marked[v]) dfs(G,v);}private void dfs(Digraph G,int v){pre.enqueue(v);marked[v] &#61; true;for(int w:G.adj(v))if(!marked[w])dfs(G,w);post.enqueue(v);reversePost.push(v);}public Iterable<Integer> pre(){return pre;}public Iterable<Integer> post(){return post;}public Iterable<Integer> reversePost(){return reversePost;}}

3 求解算法


3.1 kosaraju算法

https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm 伪代码:

  1. For each vertex u of the graph, mark u as unvisited. Let L be empty.
  2. For each vertex u of the graph do Visit(u), where Visit(u) is the recursive subroutine:
    If u is unvisited then:
    1. Mark u as visited.
    2. For each out-neighbour v of u, do Visit(v).
    3. Prepend u to L.
    Otherwise do nothing.
  3. For each element u of L in order, do Assign(u,u) where Assign(u,root) is the recursive subroutine:
    If u has not been assigned to a component then:
    1. Assign u as belonging to the component whose root is root.
    2. For each in-neighbour v of u, do Assign(v,root).
    Otherwise do nothing.

换句话说&#xff1a;
主要就是2次dfs&#xff1a;

  • 1 获得G的逆图G’&#xff0c;对G做一遍dfs获得其逆后序的顶点访问序列
  • 2 对于逆后序顶点访问序列&#xff0c;重复2.1即可
    • 2.1 将最晚完成访问的顶点&#xff0c;在G’中访问&#xff0c;能够一遍到达的那些顶点&#xff0c;就是目标的连通分量&#xff0c;将相关顶点在逆后序访问序列中移除即可

3.2 Tarjan算法&#xff08;待续&#xff09;

参考&#xff1a; https://www.cnblogs.com/wuchanming/p/4138705.html

3.3 Gabow算法(待续)

参考&#xff1a; https://www.cnblogs.com/wuchanming/p/4138705.html

具体的例子&#xff1a;

4 实际题解


4.1 针对无向图连通分量求解

该解题方案实际上为有向图强联通分量求解的一个子集&#xff0c;无向图即为顶点和顶点之间的边均为双向边。
这里以kosaraju算法为例:

  • 1 对于有向图&#xff0c;一开始我们需要获取dfs的逆序遍历栈&#xff0c;原因是&#xff0c;在第二次dfs也就是逆图中的遍历我们可以总是用最晚完成遍历的点去遍历&#xff0c;如此依赖&#xff0c;这样的一个遍历就能得到一个连通分量。
  • 2 但是针对无向图&#xff0c;不需要这样&#xff0c;因为遍历到不能拓展新的节点&#xff0c;我们就获取到了一个连通分量。

https://leetcode-cn.com/problems/number-of-provinces/
其解法如下&#xff1a;

class Solution {
public:void dfs(vector<vector<int>>& g, vector<int>& reversePost, vector<bool>& vis, int tarV) {vis[tarV] &#61; true;for(int j &#61; 0; j < g.size(); &#43;&#43;j) {if(g[tarV][j] !&#61; 0) {if(!vis[j]) {dfs(g, reversePost, vis, j);}} }reversePost.emplace_back(tarV);}int findCircleNum(vector<vector<int>>& isConnected) {// 获取逆图int n &#61; isConnected.size();vector<vector<int>> revIsConnected(isConnected);// 由于不是针对有向图&#xff0c;故不需要这一步// 获取逆序vector<bool> vis(n, false);vector<int> reversePost;// dfs(isConnected, reversePost, vis, 0);// 直接任选一点遍历&#xff0c;看有几个连通分量即可int ans &#61; 0; for(int j &#61; 0; j < isConnected.size(); &#43;&#43;j) {if(!vis[j]) {dfs(isConnected, reversePost, vis, j);ans &#43;&#43;;} }return ans;}
};// 顺便给一个并查集解法&#xff1a;
class Solution {public int findCircleNum(int[][] isConnected) {int provinces &#61; isConnected.length;int[] parent &#61; new int[provinces];for (int i &#61; 0; i < provinces; i&#43;&#43;) {parent[i] &#61; i;}for (int i &#61; 0; i < provinces; i&#43;&#43;) {for (int j &#61; i &#43; 1; j < provinces; j&#43;&#43;) {if (isConnected[i][j] &#61;&#61; 1) {union(parent, i, j);}}}int circles &#61; 0;for (int i &#61; 0; i < provinces; i&#43;&#43;) {if (parent[i] &#61;&#61; i) {circles&#43;&#43;;}}return circles;}public void union(int[] parent, int index1, int index2) {parent[find(parent, index1)] &#61; find(parent, index2);}public int find(int[] parent, int index) {if (parent[index] !&#61; index) {parent[index] &#61; find(parent, parent[index]);}return parent[index];}
}

4.2 针对有向图连通分量的求解

参考例子


推荐阅读
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 深入解析:手把手教你构建决策树算法
    本文详细介绍了机器学习中广泛应用的决策树算法,通过天气数据集的实例演示了ID3和CART算法的手动推导过程。文章长度约2000字,建议阅读时间5分钟。 ... [详细]
  • 本文深入探讨了Linux系统中网卡绑定(bonding)的七种工作模式。网卡绑定技术通过将多个物理网卡组合成一个逻辑网卡,实现网络冗余、带宽聚合和负载均衡,在生产环境中广泛应用。文章详细介绍了每种模式的特点、适用场景及配置方法。 ... [详细]
  • 机器学习中的相似度度量与模型优化
    本文探讨了机器学习中常见的相似度度量方法,包括余弦相似度、欧氏距离和马氏距离,并详细介绍了如何通过选择合适的模型复杂度和正则化来提高模型的泛化能力。此外,文章还涵盖了模型评估的各种方法和指标,以及不同分类器的工作原理和应用场景。 ... [详细]
  • 本文详细介绍了美国最具影响力的十大财团,包括洛克菲勒、摩根、花旗银行等。这些财团在历史发展过程中逐渐形成,并对美国的经济、政治和社会产生深远影响。 ... [详细]
  • 网络攻防实战:从HTTP到HTTPS的演变
    本文通过一系列日记记录了从发现漏洞到逐步加强安全措施的过程,探讨了如何应对网络攻击并最终实现全面的安全防护。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
author-avatar
zmhua123_681
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有