转 tarjan算法求强连通分量

本文介绍了Tarjan算法用于寻找图中的强连通分量,同时探讨了如何使用该算法来确定图中的割点、桥及双连通分支。

无意中想起图的强连通分量来,之前也一直想写所以今天决定来填这个坑。PS:由于本人比较懒,之前做过一个讲解的PPT,不过那是好遥远之前,年代已久早已失传,所以本文里的图来自网络。以后周末都用来填坑也挺好。

 
------------------------------分割线-----------------------------------------
 
        在有向图G中,如果两个顶点间至少存在一条路径,那么这两个顶点就是强连通(strongly connected)。
        如果有向图G的每两个顶点都强连通,称G是一个强连通图。
        非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
          例如:子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。
Tarjan算法与图的割点、桥与双连通分支 - 慕希颜 - 慕希颜的博客
       求强连通分量的方法有多种,比如你可以用双向遍历取交集,不过复杂度稍高一点O(N^2+M)。我们现在来看一种复杂度为O(N+M)的算法:Tarjan算法。代码如下:
 1 int index,bcnt;
 2 int DFN[100],LOW[100],stack[100],belong[100];
 3 bool instack[100];
 4 
 5 void tarjan(int i)
 6 {
 7 int j;
 8 DFN[i]=LOW[i]=++index;
 9 instack[i]=true;
10 stack[++top]=i;
11 for (edge *e=V[i];e;e=e->next)
12 {
13 j=e->t;
14 if (!DFN[j])// 如果节点j未被访问过
15 {
16 tarjan(j);
17 if (LOW[j]<LOW[i])
18 LOW[i]=LOW[j];
19 }
20 else if (instack[j] && DFN[j]<LOW[i])// 如果节点j还在栈内
21 LOW[i]=DFN[j];
22 }
23 if (DFN[i]==LOW[i])// 如果节点i是强连通分量的根
24 {
25 bcnt++;
26 do
27 {
28 j=stack[top--];
29 instack[j]=false;
30 belong[j]=bcnt;
31 }
32 while (j!=i);
33 }
34 }
35 void solve()
36 {
37 int i;
38 top=bcnt=index=0;
39 memset(DFN,0,sizeof(DFN));
40 for (i=1;i<=N;i++)
41 if (!DFN[i])
42 tarjan(i);
43 }

 

       Tarjan算法是基于对图的深度优先遍历,把每个强连通分量当做搜索树中的一棵子树。搜索时,把未处理的节点放到堆栈中,并借助时间戳在回溯时判断栈顶到栈中的节点是否为一个强连通分量。 
        定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。
算法执行过程如下(PS:再次强调图片来自网络,其中栈的画的不是很好,自顶向下弹栈会更直观一点,结果图弄反了):
Tarjan算法与图的割点、桥与双连通分支 - 慕希颜 - 慕希颜的博客
从节点1开始进行深度优先遍历,把每个节点加入栈中并打上时间戳,也就是该节点是第几个被访问。当我们走到节点u=6时发现DFN[6]=LOW[6],那么便开始弹栈直到u=v为止,{6}为一个强连通分量。
Tarjan算法与图的割点、桥与双连通分支 - 慕希颜 - 慕希颜的博客
同理,返回节点5时也发现DFN[5]=LOW[5],继续弹栈,{5}为一个强连通分量。
Tarjan算法与图的割点、桥与双连通分支 - 慕希颜 - 慕希颜的博客
 
 返回节点3,继续深度优先遍历到节点4,把4加入堆栈。遍历节点4的邻居节点发现虽然节点6已经出栈,但是节点1这小子还在栈中,节点4向节点1有后向边,所以LOW[4]=1。继续返回节点3,LOW[3]=LOW[4]=1。
Tarjan算法与图的割点、桥与双连通分支 - 慕希颜 - 慕希颜的博客
 
 继续回到节点1,遍历到节点2。遍历2的邻居节点,发现4还在栈中,所以LOW[2]=DFN[4]=5。返回1后,得到DFN[1]=LOW[1],所以把栈中节点全部取出,组成一个连通分量{1,3,4,2}。
至此,算法结束。得到图中的三个强连通分量{1,3,4,2},{5},{6}。
 
       以上便是Tarjan算法的执行过程。下面我们说一下图的割点、桥与双连通分支的问题。
      在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合。一个图的点连通度的定义为,最小割点集合中的顶点数。类似的,如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合。一个图的边连通度的定义为,最小割边集合中的边数。
        如果一个无向连通图的点连通度大于1,则称该图是点双连通的(point biconnected),简称双连通或重连通。一个图有割点,当且仅当这个图的点连通度为1,则割点集合的唯一元素被称为割点(cut point),又叫关节点(articulation point)。
       如果一个无向连通图的边连通度大于1,则称该图是边双连通的(edge biconnected),简称双连通或重连通。一个图有桥,当且仅当这个图的边连通度为1,则割边集合的唯一元素被称为桥(bridge),又叫关节边(articulation edge)。
        在图G的所有子图G'中,如果G'是双连通的,则称G'为双连通子图。如果一个双连通子图G'它不是任何一个双连通子图的真子集,则G'为极大双连通子图。双连通分支(biconnected component),或重连通分支,就是图的极大双连通子图。特殊的,点双连通分支又叫做块。
 
求割点与桥:
        通过上面讲的Tarjan算法有:
Low(u)=Min { DFS(u) DFS(v)}  此时(u,v)为后向边(返祖边) 即等价于 DFS(v)<DFS(u)且v不为u的父亲节点
OR 
Low(u)=Min{DFS(U) Low(v)}   此时(u,v)为树枝边(父子边)
一个顶点u是割点,则要么 u为树根,且u有多于一个子树。或者是 u不为树根,且满足存在(u,v)为父子边即u为v在搜索树中的父亲,使得DFS(u)<=Low(v)。
一条无向边(u,v)是桥,当且仅当(u,v)为树枝边,且满足DFS(u)<Low(v)。
求双连通分支:
       对于求点双连通分支,建立一个栈,存储当前双连通分支,在遍历时,每找到一条树枝边或后向边,就把这条边加入栈中。如果遇到满足DFS(u)<=Low(v)时,说明u是一个割点,此时把边从栈顶一个个取出,直到遇到了边(u,v),取出的这些边与其关联的点,组成一个点双连通分支。割点可以属于多个点双连通分支,其余点和每条边只属于且属于一个点双连通分支。
 
      对于边双连通分支,只需在求出所有的桥以后,把桥边删除,原图变成了多个连通块,则每个连通块就是一个边双连通分支。桥不属于任何一个边双连通分支,其余的边和每个顶点都属于且只属于一个边双连通分支。

转载于:https://www.cnblogs.com/do-it-best/p/5380852.html

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 本项目是本人参加BAT等其他公司电话、现场面试之后总结出来的针对Java面试的知识点或真题,每个点或题目都是在面试中被问过的。 除开知识点,一定要准备好以下套路: 个人介绍,需要准备一个1分钟的介绍,包括学习经历、工作经历、项目经历、个人优势、一句话总结。 一定要自己背得滚瓜烂熟,张口就来 抽象概念,当面试官问你是如何理解多线程的时候,你要知道从定义、来源、实现、问题、优化、应用方面系统性地回答 项目强化,至少与知识点的比例是五五开,所以必须针对简历中的两个以上的项目,形成包括【架构和实现细节】,【正常流程和异常流程的处理】,【难点+坑+复盘优化】三位一体的组合拳 压力练习,面试的时候难免紧张,可能会严重影响发挥,通过平时多找机会参与交流分享,或找人做压力面试来改善 表达练习,表达能力非常影响在面试中的表现,能否简练地将答案告诉面试官,可以通过给自己讲解的方式刻意练习 重点针对,面试官会针对简历提问,所以请针对简历上写的所有技术点进行重点准备 Java基础 JVM原理 集合 多线程 IO 问题排查 Web框架、数据库 Spring MySQL Redis 通用基础 操作系统 网络通信协议 排序算法 常用设计模式 从URL到看到网页的过程 分布式 CAP理论 锁 事务 消息队列 协调器 ID生成方式 一致性hash 限流 微服务 微服务介绍 服务发现 API网关 服务容错保护 服务配置中心 算法 数组-快速排序-第k大个数 数组-对撞指针-最大蓄水 数组-滑动窗口-最小连续子数组 数组-归并排序-合并有序数组 数组-顺时针打印矩形 数组-24点游戏 链表-链表反-链表相加 链表-...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值