热门标签 | 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 针对有向图连通分量的求解

参考例子


推荐阅读
  • 在尝试加载支持推送通知的iOS应用程序的Ad Hoc构建时,遇到了‘no valid aps-environment entitlement found for application’的错误提示。本文将探讨此错误的原因及多种可能的解决方案。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 线段树详解与实现
    本文详细介绍了线段树的基本概念及其在编程竞赛中的应用,并提供了一个具体的线段树实现代码示例。 ... [详细]
  • 题目编号:2049 [SDOI2008]Cave Exploration。题目描述了一种动态图操作场景,涉及三种基本操作:断开两个节点间的连接(destroy(a,b))、建立两个节点间的连接(connect(a,b))以及查询两节点是否连通(query(a,b))。所有操作均确保图中无环存在。 ... [详细]
  • 在Java开发中,保护代码安全是一个重要的课题。由于Java字节码容易被反编译,因此使用代码混淆工具如ProGuard变得尤为重要。本文将详细介绍如何使用ProGuard进行代码混淆,以及其基本原理和常见问题。 ... [详细]
  • 题目描述:计算从起点到终点的最小能量消耗。如果下一个单元格的风向与当前单元格相同,则消耗为0,否则为1。共有8个可能的方向。 ... [详细]
  • Vue CLI 基础入门指南
    本文详细介绍了 Vue CLI 的基础使用方法,包括环境搭建、项目创建、常见配置及路由管理等内容,适合初学者快速掌握 Vue 开发环境。 ... [详细]
  • 在Qt框架中,信号与槽机制是一种独特的组件间通信方式。本文探讨了这一机制相较于传统的C风格回调函数所具有的优势,并分析了其潜在的不足之处。 ... [详细]
  • HTML前端开发:UINavigationController与页面间数据传递详解
    本文详细介绍了如何在HTML前端开发中利用UINavigationController进行页面管理和数据传递,适合初学者和有一定基础的开发者学习。 ... [详细]
  • GLiHT数据介绍
    GLiHT数据介绍 ... [详细]
  • RTThread线程间通信
    线程中通信在裸机编程中,经常会使用全局变量进行功能间的通信,如某些功能可能由于一些操作而改变全局变量的值,另一个功能对此全局变量进行读取& ... [详细]
  • 关于进程的复习:#管道#数据的共享Managerdictlist#进程池#cpu个数1#retmap(func,iterable)#异步自带close和join#所有 ... [详细]
  • 大华股份2013届校园招聘软件算法类试题D卷
    一、填空题(共17题,每题3分,总共51分)1.设有inta5,*b,**c,执行语句c&b,b&a后,**c的值为________答:5 ... [详细]
  • 本文探讨了SSD购买后是否需要进行4K对齐的问题,并详细解释了4K对齐的原理及其重要性。通过对比机械硬盘与固态硬盘的结构,文章深入分析了4K对齐对SSD性能的影响,并提供了具体的对齐方法。 ... [详细]
  • 在iOS开发中,多线程技术的应用非常广泛,能够高效地执行多个调度任务。本文将重点介绍GCD(Grand Central Dispatch)在多线程开发中的应用,包括其函数和队列的实现细节。 ... [详细]
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社区 版权所有