强连通分量个数的最小值
- 格式:docx
- 大小:11.11 KB
- 文档页数:2
强连通分量写在前⾯:我是⼀只蒟蒻今天,我们来介绍⼀下强连通分量这个玩意⼉有向图的DFS:与⽆向图的差别就在于,搜索时只能顺边。
所以,有时的搜索树会不⽌⼀个根,因为,从⼀点出发不⼀定能⾛完所有点。
在⼀个搜索图中,每条有向边(x,y)⼀定是以下三(四)种之⼀:⽗⼦边——具有⽗⼦关系返祖边——指向其祖先横叉边——dfn[y]<dfn[x]强连通图定义给定⼀张有向图。
若对于图中任意两节点x,y,既存在x到y的路径,也存在y到x的路径,则称该有向图是“强连通图”。
强连通分量(SCC)即有向图中的极⼤强连通⼦图。
思想实现Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的⼀棵⼦树。
搜索时,把当前搜索树中未处理的节点加⼊⼀个堆栈,回溯时可以判断栈顶到栈中的节点是否为⼀个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的⼦树能够追溯到的最早的栈中节点的次序号。
当DFN(u)=Low(u)时,以u为根的搜索⼦树上所有节点是⼀个强连通分量。
下⾯我们对这个图进⾏⼀下模拟这样,我们就完成了找强连通分量的过程,下⾯我们来看⼀下核⼼代码,1void tarjan(int x){2 dfn[x]=low[x]=++num;//更新3 s[++top]=x;in[x]=1;//当前元素⼊栈4for(int i=head[x];i;i=e[i].next){5int y=e[i].to;6if(!dfn[y]){7 tarjan(y);8 low[x]=min(low[x],low[y]);9 }else{10if(in[y])low[x]=min(low[x],dfn[y]);//如果被访问过且还在栈中,更新11 }12 }13if(dfn[x]==low[x]){//是强连通分量14 cnt++;int c;//颜⾊块加⼀15do{16 c=s[top--];17 a[c]=cnt;//进⾏染⾊处理18 v[cnt]++;//当前连通块的数量统计19in[c]=0;//出栈标记20 }while(x!=c);21 }22 }OK,我们就结束了基本讲解,下⾯是两道基本栗题。
软件产品检验员理论考试1第一篇:软件产品检验员理论考试1软件产品检验员理论考试复习题判断题1.职业技能鉴定的本质是一种考试,具有考试的共性特征:是通过一定的手段对人的心理素质、社会行为表现、以及专业技能水平等方面,按一定参照系统进行检测、评估、考察或甄别,以便对人的各项表现作出比照性的评判或结论。
(T)2.职业责任包括职业团体责任和从业者个体责任两个方面。
(T)3.职业信誉是职业责任和职业良心的价值和尺度,包括对职业行为的社会价值所作出的客观评价和正确的认识。
(T)4.检验工作的依据:国家有关质量的法律、法规和规章;标准,包括国家标准、行业标准和企业标准;技术文件,包括设计文件(含图样)、工艺文件(含图样);企业质量体系文件;合同、技术协议及检验员的个人判断等。
(T)5.网终身分类标准有两种:分布范围和网络拓扑结构。
(T)6.Jackson方法适用于需求分析阶段。
(X)7.CMM 的最高级别是优化级。
(T)CMM分为五个等级:一级为初始级,二级为可重复级,三级为已定义级,四级为已管理级,五级为优化级。
8.信息建模方法是从功能的角度来建立信息模型的,最常用的描述信息模型的方法是E-R 图。
(T)9.测试的目的是尽可能多地发现软件中的错误,其附带的收获才是验证该软件已正确地实现了用户的要求。
(T)10.McCabe度量法计算公式为:V(G)=m-n+p,其中V(G)是强连通有向图G中的环数;m是G中的弧数;n是G中的节点数;p是G中分离部分的数目。
(X)11.继承概念的实现方式有三类:实现继承、接口继承和可视继承。
(T)12.代码走查一般由代码创建者来进行测试,因其对代码更加熟悉。
(P67 X)13.在实际使用中,代码检查比动态测试更有效率,能快速找到缺陷,发现30%~70%的逻辑设计和编码缺陷。
(P66 T)14.测试是为了验证软件已正确地实现了用户的要求。
(X)15.按照成分性质,程序设计语言有通用语言和专用语言之分。
求强连通分量的Kosaraju算法和Tarjan算法的比较一、定义在有向图中,如果两个顶点vi,vj间有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。
如果有向图的每两个顶点都强连通,则称该有向图是一个强连通图。
非强连通的有向图的极大强连通子图,称为强连通分量(strongly connected components)。
而对于一个无向图,讨论强连通没有意义,因为在无向图中连通就相当于强连通。
由一个强连通分量内的所有点所组成的集合称为缩点。
在有向图中的所有缩点和所有缩点之间的边所组成的集合称为该有向图的缩图。
例子:原图:缩图:上面的缩图中的缩点1包含:1、2,;缩点2包含:3;缩点3包含:4;缩点4包含:5、6、7。
二、求强连通分量的作用把有向图中具有相同性质的点找出来,形成一个集合(缩点),建立缩图,能够方便地进行其它操作,而且时间效率会大大地提高,原先对多个点的操作可以简化为对它们所属的缩点的操作。
求强连通分量常常用于求拓扑排序之前,因为原图往往有环,无法进行拓扑排序,而求强连通分量后所建立的缩图则是有向无环图,方便进行拓扑排序。
三、Kosaraju算法时间复杂度:O(M+N)注:M代表边数,N代表顶点数。
所需的数据结构:原图、反向图(若在原图中存在vi到vj的有向边,在反向图中就变成为vj到vi的有向边)、标记数组(标记是否遍历过)、一个栈(或记录顶点离开时间的数组)。
算法描叙:步骤1:对原图进行深度优先遍历,记录每个顶点的离开时间。
步骤2:选择具有最晚离开时间的顶点,对反向图进行深度优先遍历,并标记能够遍历到的顶点,这些顶点构成一个强连通分量。
步骤3:如果还有顶点没有遍历过,则继续进行步骤2,否则算法结束。
hdu1269(Kosaraju算法)代码:#include<cstdio>#include<cstdlib>const int M=10005;struct node{int vex;node *next;};node *edge1[M],*edge2[M];bool mark1[M],mark2[M];int T[M],Tcnt,Bcnt;void DFS1(int x)mark1[x]=true;node *i;for(i=edge1[x];i!=NULL;i=i->next) {if(!mark1[i->vex]){DFS1(i->vex);}}T[Tcnt]=x;Tcnt++;}void DFS2(int x){mark2[x]=true;node *i;for(i=edge2[x];i!=NULL;i=i->next) {if(!mark2[i->vex]){DFS2(i->vex);}}}int main(){int n,m;while(scanf("%d%d",&n,&m)){if(n==0&&m==0){break;}int i,a,b;for(i=1;i<=n;i++){mark1[i]=mark2[i]=false;edge1[i]=NULL;edge2[i]=NULL;}node *t;while(m--){scanf("%d%d",&a,&b);t=(node *)malloc(sizeof(node));t->vex=b;t->next=edge1[a];edge1[a]=t;t=(node *)malloc(sizeof(node));t->vex=a;t->next=edge2[b];edge2[b]=t;}Tcnt=0;for(i=1;i<=n;i++){if(!mark1[i]){DFS1(i);}}Bcnt=0;//Bcnt用于记录强连通分量的个数for(i=Tcnt-1;i>=0;i--){if(!mark2[T[i]]){DFS2(T[i]);Bcnt++;}}if(Bcnt==1)//如果强连通分量的个数为1则说明该图是强连通图{printf("Yes\n");}else{printf("No\n");}}return 0;}四、Tarjan算法时间复杂度:O(M+N)注:M代表边数,N代表顶点数。
求有向图的强连通分量个数(kosaraju算法)求有向图的强连通分量个数(kosaraju算法)1. 定义连通分量:在⽆向图中,即为连通⼦图。
上图中,总共有四个连通分量。
顶点A、B、C、D构成了⼀个连通分量,顶点E构成了⼀个连通分量,顶点F,G和H,I分别构成了两个连通分量。
强连通分量:有向图中,尽可能多的若⼲顶点组成的⼦图中,这些顶点都是相互可到达的,则这些顶点成为⼀个强连通分量。
上图中有三个强连通分量,分别是a、b、e以及f、g和c、d、h。
2. 连通分量的求解⽅法对于⼀个⽆向图的连通分量,从连通分量的任意⼀个顶点开始,进⾏⼀次DFS,⼀定能遍历这个连通分量的所有顶点。
所以,整个图的连通分量数应该等价于遍历整个图进⾏了⼏次(最外层的)DFS。
⼀次DFS中遍历的所有顶点属于同⼀个连通分量。
下⾯我们将介绍有向图的强连通分量的求解⽅法。
3. Kosaraju算法的基本原理我们⽤⼀个最简单的例⼦讲解Kosaraju算法显然上图中有两个强连通分量,即强连通分量A和强连通分量B,分别由顶点A0-A1-A2和顶点B3-B4-B5构成。
每个连通分量中有若⼲个可以相互访问的顶点(这⾥都是3个),强连通分量与强连通分量之间不会形成环,否则应该将这些连通分量看成⼀个整体,即看成同⼀个强连通分量。
我们现在试想能否按照⽆向图中求连通分量的思路求解有向图的强连通分量。
我们假设,DFS从强连通分量B的任意⼀个顶点开始,那么恰好遍历整个图需要2次DFS,和连通分量的数量相等,⽽且每次DFS遍历的顶点恰好属于同⼀个连通分量。
但是,我们若从连通分量A中任意⼀个顶点开始DFS,就不能得到正确的结果,因为此时我们只需要⼀次DFS就访问了所有的顶点。
所以,我们不应该按照顶点编号的⾃然顺序(0,1,2,……)或者任意其它顺序进⾏DFS,⽽是应该按照被指向的强连通分量的顶点排在前⾯的顺序进⾏DFS。
上图中由强连通分量A指向了强连通分量B。
计算机专业(基础综合)模拟试卷152(题后含答案及解析)题型有:1. 单项选择题 2. 综合应用题单项选择题1-40小题,每小题2分,共80分。
下列每题给出的四个选项中,只有一个选项是最符合题目要求的。
1.采用邻接表存储的图的广度优先遍历算法类似于树的( )。
A.中根遍历B.先根遍历C.后根遍历D.按层次遍历正确答案:D解析:图的深度优先遍历类似于树的先序遍历;图的广度优先遍历类似于树的层次遍历。
2.图1-1中强连通分量的个数为( )。
A.2B.3C.4D.5正确答案:C解析:在有向图G中,如果两个顶点vi、vj间有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通。
如果有向图G的每两个顶点都强连通,称G是一个强连通图。
有向图的极大强连通子图,称为强连通分量。
本题中可以看出v2、v3、v4同属于一个连通分量,另外v1、v5、v6各自属于一个强连通分量,所以共有4个强连通分量。
3.在计算机中,微程序一般存放在( )。
A.主存储器B.存储器控制器C.控制存储器D.辅助存储器正确答案:C解析:微程序存放在控制存储器中,选C。
注意存控与控存的区别,控存是用来存放微程序,而存控是用来管理协调CPU、DMA控制器等对主存储器访问的部件。
4.在I/O设备控制的发展过程中,最主要的推动因素是( )。
A.提高资源利用率B.提高系统吞吐量C.提高I/O设备与CPU的并行操作程度D.减少主机对I/O控制的干预正确答案:D5.已知循环冗余码生成多项式G(x)=x5+x4+x+1,若信息位为10101100,则冗余码是( )。
A.1101B.1100C.1101D.1100正确答案:B解析:(1)确定生成多项式G(x)=x5+x4+x+1,次数F5,对应位串110011。
(2)在信息位串后补5个0即10101100 00000,对应的多项式xrM(x),(3)用模2不借位除法,计算xrM(x)/G(x)的余数R(x),R(x)就是冗余码。
数据结构课设有向图强连通分量求解数据结构课设:有向图强连通分量求解一、引言有向图是图论中的一种重要概念,强连通分量是有向图中的一个子图,其中任意两个顶点之间都存在一条有向路径。
在数据结构课设中,我们需要实现一个算法,能够求解给定有向图的强连通分量。
二、问题描述给定一个有向图G=(V,E),其中V表示顶点的集合,E表示边的集合。
我们需要设计一个算法,能够找出图G中的所有强连通分量,并将其输出。
三、算法设计为了解决这个问题,我们可以使用Tarjan算法,该算法是一种经典的强连通分量求解算法。
下面是Tarjan算法的详细步骤:1. 初始化步骤:- 创建一个空栈S,用于存储访问过的顶点。
- 创建一个整数数组dfn和low,用于记录每个顶点的访问次序和最早访问到的祖先顶点的次序。
- 创建一个布尔数组inStack,用于标记顶点是否在栈中。
- 创建一个整数变量index,用于记录当前访问的次序。
2. 递归搜索步骤:- 遍历图中的每个顶点v,若v未被访问,则执行递归搜索函数Tarjan(v)。
- 在Tarjan(v)函数中,首先将v入栈,并标记v在栈中。
- 然后将dfn[v]和low[v]均设为index的值,并将index加1。
- 对于v的每个邻接顶点u,若u未被访问,则执行递归搜索函数Tarjan(u)。
- 在递归返回后,更新low[v]的值为v的所有邻接顶点u的low值的最小值。
- 若dfn[v]等于low[v],则说明v是一个强连通分量的根节点,将栈中的顶点依次出栈,直到v为止,并将这些顶点构成一个强连通分量。
3. 输出结果:- 将找到的所有强连通分量输出。
四、算法分析Tarjan算法的时间复杂度为O(V+E),其中V为顶点的数量,E为边的数量。
该算法通过深度优先搜索的方式遍历图中的每个顶点,同时使用dfn和low数组记录顶点的访问次序和最早访问到的祖先顶点的次序。
通过比较dfn和low数组的值,可以确定强连通分量的根节点,并将其输出。
有向图的强连通分量分类:C/C++程序设计2009-04-15 16:50 2341人阅读评论(1) 收藏举报最关键通用部分:强连通分量一定是图的深搜树的一个子树。
一、Kosaraju算法1.算法思路基本思路:这个算法可以说是最容易理解,最通用的算法,其比较关键的部分是同时应用了原图G和反图G T。
(步骤1)先用对原图G进行深搜形成森林(树),(步骤2)然后任选一棵树对其进行深搜(注意这次深搜节点A能往子节点B走的要求是E AB存在于反图G T),能遍历到的顶点就是一个强连通分量。
余下部分和原来的森林一起组成一个新的森林,继续步骤2直到没有顶点为止。
7改进思路:当然,基本思路实现起来是比较麻烦的(因为步骤2每次对一棵树进行深搜时,可能深搜到其他树上去,这是不允许的,强连通分量只能存在单棵树中(由开篇第一句话可知)),我们当然不这么做,我们可以巧妙的选择第二深搜选择的树的顺序,使其不可能深搜到其他树上去。
想象一下,如果步骤2是从森林里选择树,那么哪个树是不连通(对于G T来说)到其他树上的呢?就是最后遍历出来的树,它的根节点在步骤1的遍历中离开时间最晚,而且可知它也是该树中离开时间最晚的那个节点。
这给我们提供了很好的选择,在第一次深搜遍历时,记录时间i离开的顶点j,即numb[i]=j。
那么,我们每次只需找到没有找过的顶点中具有最晚离开时间的顶点直接深搜(对于G T来说)就可以了。
每次深搜都得到一个强连通分量。
隐藏性质:分析到这里,我们已经知道怎么求强连通分量了。
但是,大家有没有注意到我们在第二次深搜选择树的顺序有一个特点呢?如果在看上述思路的时候,你的脑子在思考,相信你已经知道了!!!它就是:如果我们把求出来的每个强连通分量收缩成一个点,并且用求出每个强连通分量的顺序来标记收缩后的节点,那么这个顺序其实就是强连通分量收缩成点后形成的有向无环图的拓扑序列。
为什么呢?首先,应该明确搜索后的图一定是有向无环图呢?废话,如果还有环,那么环上的顶点对应的所有原来图上的顶点构成一个强连通分量,而不是构成环上那么多点对应的独自的强连通分量了。
求强连通分量1、Kosaraju算法对每个不在树中的点开始DFS一次,并记录离开各点的时间,这里是离开的时间,而不是到达时的,比如有图1->2 2->3 则1,2,3分别对应的时间是3 2 1,因为3没有出边,所以最先离开,其次是2,最后是1,DFS后,在同一棵树中的点,如果dfn[v]>dfn[u]则说明点从v有可能到达u,而这棵树中的dfn[]最大的点,肯定可以到达每个点,从而在原图的逆图中,每次都选没有访问过的最大的dfn值开始DFS,如果可达点x 则说明它们是强连通的void DFS_T(int u){int i,v;if(used[u])return ;used[u]=1;id[u]=scc;for(i=q[u];i!=-1;i=Tedge[i].pre){v=Tedge[i].d;if(!used[v])DFS_T(v);}}void DFS(int v){int i,u;if(used[v])return ;used[v]=1;for(i=p[v];i!=-1;i=edge[i].pre){u=edge[i].d;if(!used[u])DFS(u);}order[++num]=v;}int Kosaraju(){int i,j,k,v,u;memset(used,0,sizeof(used));num=0;for(i=1;i<=n;++i)if(!used[i])DFS(i);memset(used,0,sizeof(used));memset(id,0,sizeof(id));scc=0;for(i=num;i>=1;--i)if(!used[order[i]])scc++,DFS_T(order[i]);}2、Tarjan算法dfn[v]记录到达点v的时间,跟上面的离开不同,low[v]表示通过它的子结点可以到达的所有点中时间最小值,即low[i]=min(low[i],low[u]),u为v的了孙,初始化时low[v]=dfn[u]。
环路识别算法
环路识别算法是指通过分析一个给定的网络或图结构,判断其中是否存在环路。
以下是几种常见的环路识别算法:
1. 深度优先搜索(DFS):从一个节点开始进行深度优先搜索,记录访问过的节点并标记为已访问。
如果在搜索路径中遇到已访问的节点,则说明存在环路。
2. 广度优先搜索(BFS):从一个节点开始进行广度优先搜索,使用队列来保存待访问的节点。
在搜索过程中,如果遇到已访问的节点,则说明存在环路。
3. 强连通分量算法:强连通分量是指一个图中的节点集合,其中的任意两个节点都可以相互到达。
通过使用强连通分量算法(如Tarjan算法或Kosaraju算法),可以将图划分为多个强连通分量。
如果存在一个强连通分量的大小大于1,则说明存在环路。
4. 拓扑排序:拓扑排序是一种对有向无环图(DAG)进行排序的算法。
在拓扑排序过程中,将入度为0的节点依次加入排序结果中,并将其邻接节点的入度减1。
如果最终排序结果包含所有的节点,则说明不存在环路;反之,存在环路。
这些算法可以根据具体的需求和应用场景进行选择和优化。
强连通分量个数的最小值
1. 引言
在图论中,强连通分量是指图中的一组顶点,其中任意两个顶点都存在一条有向路径。
强连通分量个数的最小值是指在一个有向图中,最少需要将多少个顶点组成一个强连通分量。
本文将介绍强连通分量的概念、计算方法以及如何求解强连通分量个数的最小值。
2. 强连通分量的定义
在有向图中,如果从顶点A到顶点B存在一条有向路径,同时从顶点B到顶点A也存在一条有向路径,则称顶点A和顶点B是强连通的。
如果一个有向图中的每个顶点都与其他所有顶点强连通,则该有向图被称为强连通图。
而强连通分量则是指有向图中的一组顶点,其中任意两个顶点都是强连通的,且不与其他顶点强连通。
3. 强连通分量的计算方法
为了计算一个有向图的强连通分量,可以使用强连通分量算法,其中最常用的是Tarjan算法和Kosaraju算法。
3.1 Tarjan算法
Tarjan算法是一种深度优先搜索算法,用于寻找有向图的强连通分量。
算法的基本思想是通过DFS遍历图中的每个顶点,并记录每个顶点的遍历次序和能够到达的最小顶点次序。
通过这些信息,可以判断顶点是否属于同一个强连通分量。
具体步骤如下:
1.初始化一个空栈和一个空的遍历次序数组。
2.对于每个未遍历的顶点,进行深度优先搜索。
3.搜索过程中,记录每个顶点的遍历次序和能够到达的最小顶点次序,并将顶
点加入栈中。
4.当搜索完成后,根据遍历次序和能够到达的最小顶点次序,可以确定每个顶
点所属的强连通分量。
3.2 Kosaraju算法
Kosaraju算法是另一种用于计算有向图强连通分量的算法。
算法的基本思想是通过两次深度优先搜索来确定强连通分量。
具体步骤如下:
1.对原始图进行一次深度优先搜索,记录顶点的遍历次序。
2.对原始图的转置图(即将所有边的方向反转)进行一次深度优先搜索,按照
遍历次序对顶点进行访问。
3.访问过程中,可以确定每个顶点所属的强连通分量。
4. 求解强连通分量个数的最小值
要求解强连通分量个数的最小值,可以使用以下方法:
1.使用Tarjan算法或Kosaraju算法计算有向图的强连通分量。
2.统计强连通分量的个数。
3.如果强连通分量个数为1,则最小值为1;否则,最小值为强连通分量的个
数。
5. 示例
假设有以下有向图:
A -> B
B -> C
C -> A
D -> E
E -> F
F -> D
使用Tarjan算法计算强连通分量,可以得到以下结果:
A, B, C
D, E, F
其中,第一个分量为A、B、C,第二个分量为D、E、F。
由于有两个强连通分量,
所以强连通分量个数的最小值为2。
6. 总结
强连通分量个数的最小值是指在一个有向图中,最少需要将多少个顶点组成一个强连通分量。
通过使用Tarjan算法或Kosaraju算法,可以计算有向图的强连通分量,并统计分量的个数。
根据分量个数的大小,可以求解强连通分量个数的最小值。
强连通分量的概念和计算方法在图论中具有重要的应用价值,对于分析有向图的结构和性质具有重要意义。