判断一个图是否有环 无向图 有向图

合集下载

算法之判断一个图是否有环

算法之判断一个图是否有环

算法之判断⼀个图是否有环在⼀些经典算法中,经常需要判断⼀些图是否具有环路,⽐如拓扑排序,需要在最初判断该图是否有环路,如有有环路,则⽆法找到最长的⼀条线,⽐如dijkstra算法,每找到⼀条最短的边,都要判断找到的边和现有的树是否已经构成了环路。

因此,在这篇博客,我们重点来说⼀个判断图是否有环的算法。

⾸先我们介绍⼀个对于⽆向图和有向图通⽤的算法,先讲算法思路: 1.统计各个图中各个点的⼊度数(能够到达这个点的点的数量)。

2.然后找出⼊度数为0的点(⽆向图找⼊度数为1的点)。

3.删除⼊度数为0的点,将其边也删除。

4.重复2,直到所有点⼊度都为0,则为⽆环图,如果找不到⼊度为0的点,则为有环图。

该算法的精髓在于对于⼀个环路(以有向图为例),1->2,2->3,3->1,你会发现找不到⼀个⼊度为0的点,因此这个⽅法是可⾏的。

对于⽆向图和有向图来说,这个算法是通⽤的。

在这我只写了对于有向图的判断的算法,具体的实现代码如下:#include<stdio.h>using namespace std;int graph[100][100];//⽤来存储图的数组bool isVisited[100];//判断这个点是否已经删除int main(){int n,e;while (scanf("%d",&n)!=EOF&&n!=0)//获取点数{for(int i = 0;i<100;i++){isVisited[i] = false;for(int j = 0 ;j<100;j++){graph[i][j] = -1;//初始化数据,所有的边都为-1,代表这两个点之间不能联通}}scanf("%d",&e);//获取边数for(int i = 0 ;i<e;i++)//构建图{int a,b,c;scanf("%d %d %d",&a,&b,&c);graph[a-1][b-1] = c;}int isResult = true;for(int i = 0 ;i<n;i++)//进⾏n次循环,每次循环删除⼀个⼊度为0的点,所以进⾏n次循环{for(int j = 0;j<n;j++)//遍历所有的点,找⼊度为0的点{if(!isVisited[j])//判断该点是否删除{bool isCanVisited = true;//辅助变量,判断这个点是否⼊度为0for(int k = 0;k<n ;k++){if(graph[k][j]!=-1){isCanVisited = false;//如果存在能够访问这个点的边,则该点⼊度不为0}}if(isCanVisited)//如果该点⼊度为0,则下边是删除该点和删除其相邻边{for(int k = 0 ;k<n;k++){graph[j][k] = -1;//删除相邻边,即将值变为-1}isVisited[j] = true;//删除该点}}}isResult = true;for(int j = 0 ;j<n;j++)//进⾏循环判断当前多有点是否已经全部删除,如果全部删除,如果全部删除则跳出,否则继续循环{if(!isVisited[j]){isResult = false;}}if(isResult)break;}isResult = true;for(int i = 0 ;i<n;i++)//在所有点遍历后,则通过这个循环来判断是否所有点都已经删除,如果全部删除,则为⽆环图,否则为有环图{if(!isVisited[i])isResult = false;}if(isResult)printf("⽆环");if(!isResult)printf("有环");}return 0;}实验数据(第⼀⾏输⼊n,e,n代表的是点数,e代表的是边数,接下来e⾏代表具体的边和其权值(权值暂时不⽤理会,是后续拓扑排序所有,因此当前暂时都为1)):5 41 2 11 3 12 3 14 5 15 41 2 12 1 12 3 14 5 1实验结果:。

图习题-数据结构

图习题-数据结构

习题七图一、单项选择题1.设有无向图G=(V,E)和G’=(V’,E’),如G’为G的生成树,则下面不正确的说法是()A.G’为G的子图 B.G’为G的连通分量C.G’为G的极小连通子图且V’=V D.G’是G的无环子图2.任何一个带权的无向连通图的最小生成树()A.只有一棵 B.有一棵或多棵 C.一定有多棵 D.可能不存在3.以下说法正确的是()A.连通分量是无向图中的极小连通子图。

B.强连通分量是有向图中的极大强连通子图。

C.在一个有向图的拓扑序列中,若顶点a在顶点b之前,则图中必有一条弧<a,b>。

D.对有向图G,如果从任意顶点出发进行一次深度优先或广度优先搜索能访问到每个顶点,则该图一定是完全图。

4.图中有关路径的定义是()。

A.由顶点和相邻顶点序偶构成的边所形成的序列 B.由不同顶点所形成的序列C.由不同边所形成的序列 D.上述定义都不是5.设无向图的顶点个数为n,则该图最多有()条边。

A.n-1 B.n(n-1)/2 C. n(n+1)/2 D.0 E.n26.要连通具有n个顶点的有向图,至少需要()条边。

A.n-l B.n C.n+l D.2n7.在一个无向图中,所有顶点的度数之和等于所有边数()倍,在一个有向图中,所有顶点的入度之和等于所有顶点出度之和的()倍。

A.1/2 B.2 C.1 D.48.下列哪一种图的邻接矩阵是对称矩阵?()A.有向图 B.无向图 C.AOV网 D.AOE网9. 下列说法不正确的是()。

A.图的遍历是从给定的源点出发每一个顶点仅被访问一次B.遍历的基本算法有两种:深度遍历和广度遍历C.图的深度遍历不适用于有向图D.图的深度遍历是一个递归过程10.下面哪一方法可以判断出一个有向图是否有环(回路):A.深度优先遍历 B. 拓扑排序 C. 求最短路径 D. 求关键路径11. 在图采用邻接表存储时,求最小生成树的 Prim 算法的时间复杂度为( )。

拓扑排序——判断有向图中是否存在环

拓扑排序——判断有向图中是否存在环

拓扑排序——判断有向图中是否存在环 1// 将先修关系构成⼀张图,由每个数对的第⼆个数字向第⼀个数字连边。

2// ⾸先将所有⼊度为0的点进队,准备拓扑排序。

3// 宽搜过程中,将当前结点所关联的结点的⼊度减1;若发现新的⼊度为0的结点,则将其进队。

4// 最后如果遍历了所有结点,则说明可以满⾜要求;否则,先修关系存在环。

56//查找是否有环7class Solution8 {9public:10bool canFinish(int numCourses, vector<vector<int>>& prerequisites)11 {12 vector<vector<int>> graph(numCourses);13 vector<int> in_degree(numCourses, 0);14for (int i = 0; i < prerequisites.size(); i++)15 {16 in_degree[prerequisites[i][0]]++;17 graph[prerequisites[i][1]].push_back(prerequisites[i][0]);18 }1920 queue<int> q;21 vector<bool> vis(numCourses, false);2223for (int i = 0; i < numCourses; i++)24if (in_degree[i] == 0)25 q.push(i);26while (!q.empty())27 {28int sta = q.front();29 q.pop();30 vis[sta] = true;31//有哪些邻边32for (int i = 0; i < graph[sta].size(); i++)33 {34 in_degree[graph[sta][i]]--;// ⼊度-135if (in_degree[graph[sta][i]] == 0) //⼊度如果为0,加⼊队列36 q.push(graph[sta][i]);37 }38 }3940//0->1->241for (int i = 0; i < numCourses; i++)42if (vis[i] == false)43return false;//有环44return true;//⽆环45 }46 };。

第7章 图-有向无环图

第7章 图-有向无环图

算法的执行步骤: 算法的执行步骤: 1、用一个数组记录每个结点的入度。将入度为零的 、用一个数组记录每个结点的入度。 结点进栈。 结点进栈。 2、将栈中入度为零的结点V输出。 、将栈中入度为零的结点 输出 输出。 3、根据邻接表找到结点 的所有的邻接结点, 并将 、根据邻接表找到结点V的所有的邻接结点 的所有的邻接结点, 这些邻接结点的入度减一。 这些邻接结点的入度减一 。 如果某一结点的入度变 为零,则进栈。 为零,则进栈。
3
2
3、找到全为零的第 k 列,输出 k 、 4、将第 k 行的全部元素置为零 、 行的全部元素置为零
…………………
7
53、4;直至所有元素输出完毕。 、 ;直至所有元素输出完毕。
1 2 3 4 5 6 7
0 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0
template<class T> int BinaryTree <T>:: NumOfOne ( node <T> *t )
{ int k=0; if (t==NULL ) //空二叉树 //空二叉树 return 0; if (t所指结点 的度为 k=1 所指结点 的度为1) k=1; d1= NumOfOne ( t->lchild); //递归求左子树叶结点数 //递归求左子树叶结点数 d2= NumOfOne ( t->rchild); } //递归求右子树叶结点数 //递归求右子树叶结点数 return (d1+d2+k);
A B
AOE网络:结点为事件,有向边指向表示事件的执行次序。 网络:结点为事件,有向边指向表示事件的执行次序。 网络 有向边定义为活动,边的权值为活动进行所需要的时间。 有向边定义为活动,边的权值为活动进行所需要的时间。

图论及其应用习题答案

图论及其应用习题答案

图论及其应用习题答案图论及其应用习题答案图论是数学的一个分支,研究的是图的性质和图之间的关系。

图是由节点和边组成的,节点表示对象,边表示对象之间的关系。

图论在计算机科学、电子工程、物理学等领域有着广泛的应用。

下面是一些图论习题的解答,希望对读者有所帮助。

1. 问题:给定一个无向图G,求图中的最大连通子图的节点数。

解答:最大连通子图的节点数等于图中的连通分量个数。

连通分量是指在图中,任意两个节点之间存在路径相连。

我们可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来遍历图,统计连通分量的个数。

2. 问题:给定一个有向图G,判断是否存在从节点A到节点B的路径。

解答:我们可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来遍历图,查找从节点A到节点B的路径。

如果能够找到一条路径,则存在从节点A到节点B的路径;否则,不存在。

3. 问题:给定一个有向图G,判断是否存在环。

解答:我们可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来遍历图,同时记录遍历过程中的访问状态。

如果在搜索过程中遇到已经访问过的节点,则存在环;否则,不存在。

4. 问题:给定一个加权无向图G,求图中的最小生成树。

解答:最小生成树是指在无向图中,选择一部分边,使得这些边连接了图中的所有节点,并且总权重最小。

我们可以使用Prim算法或Kruskal算法来求解最小生成树。

5. 问题:给定一个有向图G,求图中的拓扑排序。

解答:拓扑排序是指将有向图中的节点线性排序,使得对于任意一条有向边(u, v),节点u在排序中出现在节点v之前。

我们可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来遍历图,同时记录节点的访问顺序,得到拓扑排序。

6. 问题:给定一个加权有向图G和两个节点A、B,求从节点A到节点B的最短路径。

解答:我们可以使用Dijkstra算法或Bellman-Ford算法来求解从节点A到节点B的最短路径。

这些算法会根据边的权重来计算最短路径。

图论选择题解析docx

图论选择题解析docx

数据结构——图选择题整理1.设完全图Kn,有n个结点(n≥2),m条边,当()时,K,中存在欧拉回路。

A.m为奇数B.n为偶数C.n为奇数D.m为偶数解析:答案C完全图是一个简单的无向图,其中每对不同的顶点之间都恰连有一条边相连。

n 个端点的完全图有n个端点以及n(n-1)/2条边,因此完全图Kn的每个结点的度都为n-1,所以若存在欧拉回路则n-1必为偶数。

n必为奇数。

选C。

2、若从无向图的任意顶点出发进行一次深度优先搜索即可访问所有顶点,则该图一定是()A、强连通图B、连通图C、有回路D、一棵树解析:选B对于A,强连通图的概念是在有向图中的。

对于B,连通图证明任意两个顶点之间一定能够相连,因此一定可以到达。

对于C,有环图不一定是连通图不一定任意两个顶点均能到达。

对于D,树是可以,但是不是树也可以,题目中说的太肯定了,不能选,比如下图就不是树,但可以完成题目中要求的功能。

2、对于一个有n个顶点的图:若是连通无向图,其边的个数至少为();若是强连通有向图,其边的个数至少为()A、n-1,nB、n-1,n(n-1)C、n,nD、n,n(n-1)解析:选A对于连通无向图,至少需要n-1条边。

对于强连通有向图,只要能形成一个大环就可以从任意一点到另一点。

3、设有无向图G=(V,E)和G'=(V',E'),若G’是G的生成树,则下列不正确的是()a.G'为G的连通分量b.G'为G的无环子图c.G'为G的极小连通子图且V'=VA、a和bB、只有cC、b和cD、只有a解析:选D极大连通子图简称连通分量,生成树是极小连通子图。

故a不对,c对。

生成树无环,故b对4.带权有向图G用邻接矩阵存储,则vi的入度等于邻接矩阵中()A、第i行非∞的元素个数B、第i列非∞的元素个数C、第i行非∞且非0的元素个数D、第i列非∞且非0的元素个数解析:选D带权有向图的邻接矩阵中,非0和∞的数字表示两点间边的权值。

有向图与无向图的性质与算法

有向图与无向图的性质与算法

有向图与无向图的性质与算法1. 引言在图论中,有向图和无向图是两种最基本的图模型。

它们在表达和解决各类实际问题时具有重要的应用价值。

本文将介绍有向图和无向图的性质以及相关算法,以便读者对其有更深入的理解。

2. 有向图的性质有向图是由一系列顶点和有方向的边组成的图模型。

以下是有向图的几个重要性质:2.1 有向边的方向性与无向图不同,有向图中的边是有方向的,它们从一个顶点指向另一个顶点。

这种方向性在描述一些实际问题时非常有用,比如描述物流运输的路径。

2.2 顶点的入度和出度有向图中的每个顶点都有一个入度和一个出度。

顶点的入度是指指向该顶点的边的数量,而出度是指从该顶点出发的边的数量。

通过计算入度和出度,我们可以了解顶点在图中的连接情况。

2.3 有向环和拓扑排序有向图中存在一个重要的概念,即有向环。

有向环是指从一个顶点出发,经过若干个有向边后又回到该顶点的路径。

有向环在一些问题的分析和解决中具有特殊意义。

而拓扑排序是一种常用的对有向无环图进行排序的方法,它可以按照顶点之间的依赖关系进行排序。

3. 无向图的性质无向图是由一系列顶点和无方向的边组成的图模型。

以下是无向图的几个重要性质:3.1 无向边的无方向性与有向图不同,无向图中的边是无方向的,它们连接着两个顶点,代表了两个顶点之间的关系。

无向图可以用来表示一些没有方向性的问题,比如社交网络中的好友关系。

3.2 顶点的度数无向图中的顶点的度数是指与该顶点相连的边的数量。

顶点的度数越高,说明该顶点在图中的重要性越高,具有更多的连接关系。

3.3 联通性和连通分量无向图中有一个关键性质,即联通性。

若两个顶点之间存在一条连接它们的路径,则称这两个顶点是连通的。

连通分量则是将图中所有连通的顶点分为若干个集合,每个集合内的顶点都是连通的。

4. 算法与应用4.1 有向图的最短路径算法有向图中的最短路径算法是指寻找从一个顶点到另一个顶点的最短路径的方法。

其中,Dijkstra算法和Bellman-Ford算法是常用的有向图最短路径算法。

数据结构考前复习3

数据结构考前复习3

第四章串一、选择题1.下面关于串的的叙述中,哪一个是不正确的?( B )A.串是字符的有限序列 B.空串是由空格构成的串C.模式匹配是串的一种重要运算 D.串既可以采用顺序存储,也可以采用链式存储3.设有两个串p和q,其中q是p的子串,求q在p中首次出现的位置的算法称为( C )A.求子串 B.联接 C.匹配 D.求串长10.串的长度是指( B )A.串中所含不同字母的个数 B.串中所含字符的个数C.串中所含不同字符的个数 D.串中所含非空格字符的个数二、填空题1.空格串是指由空格字符(ASCII值32)所组成的字符串,其长度等于空格个数__。

2.组成串的数据元素只能是__字符______。

3.一个字符串中任意个连续的字符组成的子序列称为该串的子串。

四、应用题1.名词解释:串串是零个至多个字符组成的有限序列。

从数据结构角度讲,串属于线性结构。

与线性表的特殊性在于串的元素是字符。

2.描述以下概念的区别:空格串与空串。

空格是一个字符,其ASCII码值是32。

空格串是由空格组成的串,其长度等于空格的个数。

空串是不含任何字符的串,即空串的长度是零。

第六章树和二叉树一、选择题1.已知一算术表达式的中缀形式为 A+B*C-D/E,后缀形式为ABC*+DE/-,其前缀形式为( D )A.-A+B*C/DE B. -A+B*CD/E C.-+*ABC/DE D. -+A*BC/DE 4. 设树T的度为4,其中度为1,2,3和4的结点个数分别为4,2,1,1 则T中的叶子数为( D )A.5 B.6 C.7 D.85. 在下述结论中,正确的是( D )①只有一个结点的二叉树的度为0; ②二叉树的度为2;③二叉树的左右子树可任意交换;④深度为K的完全二叉树的结点个数小于或等于深度相同的满二叉树。

A.①②③ B.②③④ C.②④ D.①④结点的度:一个结点的子数个数称为此结点的度数的度;树中所有结点的读的最大值6. 设森林F对应的二叉树为B,它有m个结点,B的根为p,p的右子树结点个数为n,森林F中第一棵树的结点个数是( A )A.m-n B.m-n-1 C.n+1 D.条件不足,无法确定8.若一棵二叉树具有10个度为2的结点,5个度为1的结点,则度为0的结点个数是( B )A.9 B.11 C.15 D.不确定10.设森林F中有三棵树,第一,第二,第三棵树的结点个数分别为M1,M2和M3。

信息学奥赛1003题

信息学奥赛1003题

信息学奥赛1003题
题目一:在一个有向图中,如何求出从节点A到节点B的所有路径?
解答:首先,我们可以使用深度优先搜索(DFS)来求解。

从节点A开始,依次遍历与其相邻的节点,直至遍历到节点B为止。

在遍历的过程中,需要记录下已经经过的路径,以避免重复访问节点。

当找到一条从节点A到节点B的路径后,将其记录下来。

继续遍历直到将所有路径都找出来为止。

题目二:如何判断一个图中是否存在环?
解答:若是一个有向图,可以使用深度优先搜索(DFS)或广度优先搜索(BFS)遍历整个图,如果在遍历的过程中遇到了已经访问过的节点,则说明存在环。

如果是无向图,则可以使用并查集(Union-Find)来判断是否存在环,具体方法是在遍历每一条边的同时,判断这两个节点是否已经连通,如果已经连通,则说明存在环。

题目三:如何求解最短路径?
解答:在一个有向图中,可以使用Dijkstra算法或者Bellman-Ford算法来求解最短路径。

Dijkstra算法适用于边权值非负的情况,通过不断更新起点到其他节点的最短距离来求解最短路径。

而Bellman-Ford算法则适用于存在负权边的情况,通过不断松弛边来求解最短路径。

需要注意的是,在使用Bellman-Ford算法时,需要判断是否存在负环路。

以上就是关于信息学奥赛1003题的解答,希望对大家有所帮助。

如果还有其他问题,欢迎继续提出讨论。

有向无环图——精选推荐

有向无环图——精选推荐

有向⽆环图有向⽆环图有向图是由顶点和有向边组成的,有向边由上游点和下游点组成,⽐如(u,v)表⽰⼀个有向边,其中u就是该有向边的上游点,v就是该有向边的下游点,⼊度是指⼀个顶点作为下游点所在有向边的个数,⽐如下图中,顶点1的⼊度是0,顶点3的⼊度是1,顶点6的⼊度是2,出度是指⼀个顶点作为上游点所在有向边的个数,⽐如顶点1的出度是1,顶点3的出度是2.有向⽆环图就是不存在环形的有向图,即不存在任何⼀个从某个顶点出发,经过⼀条或者多条边后,重新⼜回到了出发点的路径。

有向图的拓扑排序是指这样⼀个线性序列:如果(u,v)是有向⽆环图中的⼀条边,那么在线性序列中,u必须出现在v之前。

利⽤拓扑排序所产⽣的线性序列不⼀定是唯⼀的。

⽐如下图的拓扑顺序可以是:9->10->2->1->3->5->4->6->11->12->7->8->13->14,也可以是1->3->2->4->5->6->9->10->11->12->7->8->13->14.那么如何给出⼀个有向⽆环的拓扑排序?伪代码如下:输⼊:G:⼀个顶点编号为从1~n的有向⽆环图;输出:关于该图的⼀个拓扑序列;步骤:1.构造⼀个⼊度数组,in-degree,根据G,填充该⼊度数组;2.将⼊度数组中的每个⼊度值为0的顶点,压⼊next栈;3.只要next不为空,执⾏如下操作:A.从next中弹出⼀个顶点uB.将u添加到线性序列的末尾处C.对于每个与u邻接的下游点v:i.令in-dgree[v]的值⾃减1ii. 如果in-degree[v]=0,将v压⼊next栈中4.返回线性序列该伪代码的核⼼思想就是移除⼊度为0的顶点,以及其所在的有向边,与该点邻接的下游点的⼊度均减⼀,那么剩下的图仍然是有向⽆环图,反复操作,就得到了线性序列。

判断有向图是否有环

判断有向图是否有环

判断有向图是否有环如何判断有向图是否有环1.dfs,bfs2.拓扑排序使⽤拓扑排序来解决这个问题,⾸先什么是拓扑排序?⼀直删除出度为0的顶点直到没有出度为0的顶点,如果最终还有顶点存在就说明有环,并且是由剩下的顶点组成的环。

例如有有向图的邻接表如下0->11->01->22->3⾸先 3这个顶点出度为 0那先删除跟3有关的邻接表,剩下的邻接表有0->11->01->2然后 2这个顶点出度为0,删除跟2有关的邻接表,剩下的邻接表有0->11->0已经没有出度为0的邻接表了,剩下的0,1组成了有向图的环代码实现// 有向图是否有环func canFinish(numCourses int, prerequisites [][]int) bool {// 邻接表mapadj := make(map[int]map[int]struct{}, numCourses)// 反向邻接表mapadjR := make(map[int]map[int]struct{}, numCourses)for i := 0; i < len(prerequisites); i++ {_, ok := adj[prerequisites[i][1]]if !ok {adj[prerequisites[i][1]] = make(map[int]struct{}, numCourses)}_, ok = adjR[prerequisites[i][0]]if !ok {adjR[prerequisites[i][0]] = make(map[int]struct{}, numCourses)}adj[prerequisites[i][1]][prerequisites[i][0]] = struct{}{}adjR[prerequisites[i][0]][prerequisites[i][1]] = struct{}{}}// 所有顶点集合mapg := make(map[int]struct{}, numCourses)for i := 0; i < numCourses; i++ {g[i] = struct{}{}}return !topology(adj, adjR, g)}// 图的拓扑排序⼀直删除出度为0的顶点直到所有顶点出度⼤于0或者没有顶点了func topology(adj, adjR map[int]map[int]struct{}, g map[int]struct{}) bool {var existsZero boolfor k := range g {// 出度为0 删除这个节点if _, ok := adj[k]; !ok {existsZero = truedelete(g, k)mr, ok1 := adjR[k]if ok1 {for i := range mr {delete(adj[i], k)if len(adj[i]) == 0 {delete(adj, i)}}delete(adjR, k)}}}if len(g) > 0 && existsZero { return topology(adj, adjR, g) }if len(g) > 0 && !existsZero { return true}return false}。

数据结构第7章图习题

数据结构第7章图习题

第七章图习题1 单项选择题1、图中有关路径的定义是()。

A、由顶点和相邻顶点序偶构成的边所形成的序列B、由不同顶点所形成的序列C、由不同边所形成的序列D、上述定义都不对2、设无向图的顶点个数为n,则该图最多有()条边。

A、n– 1B、n (n– 1)/2C、n (n+1)/2D、n23、一个n个顶点的连通无向图,其边的个数至少为()。

A、n– 1B、nC、n+1D、n log n4、下面结构中最适于表示稀疏无向图的是()。

A、邻接矩阵B、逆邻接表C、邻接多重表D、十字链表5、下列哪一种图的邻接矩阵是对称矩阵?()A、有向图B、无向图C、AOV网D、AOE网6、当一个有N个顶点的图用邻接矩阵A表示时,顶点V i的度是()。

A、第j列所有元素之和B、第i行所有元素之和C、不确定D、第j列所有元素之和+第i行所有元素之和7、下面哪一方法可以判断出一个有向图是否有环(回路)()。

A、深度优先遍历B、拓扑排序C、求最短路径D、求关键路径8、在图采用邻接表存储时,求最小生成树的Prim 算法的时间复杂度为( )。

A、O(n)B、O(n+e)C、O(n2)D、O(n3)9、求解最短路径的Floyd算法的时间复杂度为( )。

A、O(n)B、O(n+e)C、O(n2)D、O(n3)10、已知有向图G=(V, E),其中V={v1, v2, v3, v4, v5, v6, v7},E={<v1,v2>, <v1,v3>, <v1,v4>, <v2,v5>, <v3,v5>, <v3,v6>, <v4,v6>, <v5,v7>, <v6,v7>}, G的拓扑序列是()。

A、v1,v3,v4,v6,v2,v5,v7B、v1,v3,v2,v6,v4,v5,v7C 、v 1,v ,v 4,v 5,v 2,v 6,v 7D 、v 1,v 2,v 5,v 3,v 4,v 6,v 711、在用邻接表表示图时,拓扑排序算法时间复杂度为( )。

判断一个图是否有环

判断一个图是否有环

判断⼀个图是否有环对于⽆向图算法1我们知道对于环1-2-3-4-1,每个节点的度都是2,基于此我们有如下算法(这是类似于有向图的拓扑排序):1. 求出图中所有顶点的度,2. 删除图中所有度<=1的顶点以及与该顶点相关的边,把与这些边相关的顶点的度减⼀3. 如果还有度<=1的顶点重复步骤24. 最后如果还存在未被删除的顶点,则表⽰有环;否则没有环时间复杂度为O(E+V),其中E、V分别为图中边和顶点的数⽬,这个算法我们稍后分析算法3的时候再分析。

算法2深度优先遍历该图,如果在遍历的过程中,发现某个节点有⼀条边指向已经访问过的节点,并且这个已访问过的节点不是当前节点的⽗节点(这⾥的⽗节点表⽰dfs遍历顺序中的⽗节点),则表⽰存在环。

但是我们不能仅仅使⽤⼀个bool数组来标志节点是否访问过。

如下图从节点1开始遍历-接着遍历2-接着遍历3,然后发现3有⼀条边指向遍历过的1,则存在环。

但是回到1节点时,它的另⼀条边指向已访问过的3,⼜把这个环重复计算了⼀次。

我们按照算法导论22.3节深度优先搜索中,对每个节点分为三种状态,⽩、灰、⿊。

开始时所有节点都是⽩⾊,当开始访问某个节点时该节点变为灰⾊,当该节点的所有邻接点都访问完,该节点颜⾊变为⿊⾊。

那么我们的算法则为:如果遍历的过程中发现某个节点有⼀条边指向颜⾊为灰的节点,那么存在环。

则在上⾯的例⼦中,回溯到1节点时,虽然有⼀条边指向已经访问过的3,但是3已经是⿊⾊,所以环不会被重复计算。

下⾯的代码中visit数组的值分为0 1 2三种状态分别代表⽩⾊、灰⾊、⿊⾊,调⽤函数dfs可以输出图中存在的所有环,图⽤邻接矩阵表⽰,如果两个节点之间没有边则对应的值为INT_MAXvoid dfsVisit(vector<vector<int> >&graph, int node, vector<int>&visit,vector<int>&father){int n = graph.size();visit[node] = 1;//cout<<node<<"-\n";for(int i = 0; i < n; i++)if(i != node && graph[node][i] != INT_MAX){if(visit[i] == 1 && i != father[node])//找到⼀个环{int tmp = node;cout<<"cycle: ";while(tmp != i){cout<<tmp<<"->";tmp = father[tmp];}cout<<tmp<<endl;}else if(visit[i] == 0){father[i] = node;dfsVisit(graph, i, visit, father);}}visit[node] = 2;}void dfs(vector<vector<int> >&graph){int n = graph.size();vector<int> visit(n, 0); //visit按照算法导论22.3节分为三种状态vector<int> father(n, -1);// father[i] 记录遍历过程中i的⽗节点for(int i = 0; i < n; i++)if(visit[i] == 0)dfsVisit(graph, i, visit, father);}算法时间复杂度也是O(E+V)对于有向图算法3我们都知道对于有向图进⾏拓扑排序可以判断是否存在环。

有向无环图及其应用

有向无环图及其应用

有向树, 图7.15 有向树,DAG图和有向图一例 图和有向图一例
(2)表达式子式共享 ) 例如,下述表达式 例如,下述表达式((a +b ) * (b * (c + d)) + (c + d) * e) * ((c + d) * e),用 , 二叉树表示如图7.16所示,用有向无环图表示如图7.17所示. 所示, 所示. 二叉树表示如图 所示 用有向无环图表示如图 所示 * + * + a b b c * + d 图7.16 用二叉树描述表达式 c + d * e c + d * e
count = 0; while (!StackEmpty (S)) { Pop (S, i); printf (i, G.vertices[i].data); //输出 号顶点并计数 输出i号顶点并计数 输出 ++ count; for (p = G.vertices[i].firstarc; p; p = p->nextarc) { - k = p->adjvex; //对i号顶点的每个邻接点的入度减 号顶点的每个邻接点的入度减1 - 对 号顶点的每个邻接点的入度减 if (!(――indegree[k])) Push (S, k); //若入度减为 ,则入栈 若入度减为0, 若入度减为 } // for } // while if (count < G.vexnum) return ERROR; //该有向图有回路 该有向图有回路 } // TopologicalSort
v6 → v1 → v 4 → v3 → v 2 → v5
£7.5.3 关键路径
(1)定义 ) 关键路径( ):在 网中有些活动可以并行的进行, 关键路径(Critical Path):在AOE-网中有些活动可以并行的进行, ): 网中有些活动可以并行的进行 所以完成工程的最短时间是从开始点到完成点的最长路径的长度( 所以完成工程的最短时间是从开始点到完成点的最长路径的长度(路径 长度是指路径上各活动持续时间之和,而不是路径上弧的数目). ).这个 长度是指路径上各活动持续时间之和,而不是路径上弧的数目).这个 路径长度最长的路径叫关键路径. 路径长度最长的路径叫关键路径. 关键活动: 的活动. 关键活动:l(i) = e(i)的活动.即活动的最早开始时间=最迟开始时间. 的活动 即活动的最早开始时间=最迟开始时间. 显然,关键路径上的所有活动都是关键活动. 显然,关键路径上的所有活动都是关键活动. (2)AOE-网 ) 网 AOE-网(Activity On Edge):即边表示活动的网.AOE-网是一个 网 ):即边表示活动的网 ):即边表示活动的网. 网是一个 带权的有向无环图.其中,顶点表示事件(Event),弧表示活动,权 带权的有向无环图.其中,顶点表示事件( ),弧表示活动, ),弧表示活动 表示活动持续的时间. 表示活动持续的时间.

图论:有向图和无向图,有环和无环

图论:有向图和无向图,有环和无环

图论:有向图和⽆向图,有环和⽆环
有向⽆环图:为什么不能有环,有环会导致死循环。

检查⼀个有向图是否存在环要⽐⽆向图复杂。

(有向图为什么⽐⽆向图检查环复杂呢?)
现实中管⽹会存在环吗?管⽹是有⽅向的,理论上也是⽆环的。

arcgis有向⽆环图最短路径。

有向⽆环图和⼆叉树的关系:如何确定⽗节点和⼦节点[没有⽗节点的就是⽗节点,没有⼦节点的就是叶⼦节点] 有向⽆环图并不⼀定能转化成树【那能不能把有向⽆环图劈开成多棵树】
⼀个⽆环的有向图称做有向⽆环图(Directed Acyclic Graph)。

简称DAG 图。

DAG 图是⼀类较有向树更⼀般的特殊有向图,如图给出了有向树、DAG 图和有向图的例⼦。

虽然DAG图是更⼀般的有向图,但是依然可以使⽤树的判断公式来判断复杂度。

判断是否有环:
1. 起点编码和终点编码是否相等
从OBJECTID为1的开始遍历:下⼀个点是否与OBJECTID为1的相等。

如果相等,则回到起点,为环。

>>性质:有向⽆环图的⽣成树个数等于⼊度⾮零的节点的⼊度积。

有向⽆环图⽣成树:
(百度百科上不是说有向⽆环图不⼀定能转换成树吗?严格意义上,树的叶⼦节点只有⼀个⽗节点)
DAG(有向⽆环图)能否转化为树?:
如果说⼀个叶⼦节点有两个⽗节点,会怎么样
有向⽆环图不⼀定能只⽣成⼀棵树,但是可以⽣成多棵树。

但是这样就破坏了什么信息呢?。

判断一个图是否有环无向图有向图讲解

判断一个图是否有环无向图有向图讲解

一、无向图:方法1:∙如果存在回路,则必存在一个子图,是一个环路。

环路中所有顶点的度>=2。

∙ n算法:第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

如果最后还有未删除顶点,则存在环,否则没有环。

∙ n算法分析:由于有m条边,n个顶点。

i)如果m>=n,则根据图论知识可直接判断存在环路。

(证明:如果没有环路,则该图必然是k棵树k>=1。

根据树的性质,边的数目m = n-k。

k>=1,所以:m<n)ii)如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。

这两种操作的总数不会超过m+n。

由于m<n,所以算法复杂度为O(n)。

∙注:该方法,算法复杂度不止O(V),首先初始时刻统计所有顶点的度的时候,复杂度为(V + E),即使在后来的循环中E>=V,这样算法的复杂度也只能为O(V + E)。

其次,在每次循环时,删除度为1的顶点,那么就必须将与这个顶点相连的点的度减一,并且执行delete node from list[list[node]],这里查找的复杂度为list[list[node]]的长度,只有这样才能保证当degree[i]=1时,list[i]里面只有一个点。

这样最差的复杂度就为O(EV)了。

方法2:DFS搜索图,图中的边只可能是树边或反向边,一旦发现反向边,则表明存在环。

该算法的复杂度为O(V)。

方法3:摘自:/lzrzhao/archive/2008/03/13/2175787.aspx PS:此方法于2011-6-12补充假定:图顶点个数为M,边条数为E遍历一遍,判断图分为几部分(假定为P部分,即图有P 个连通分量)对于每一个连通分量,如果无环则只能是树,即:边数=结点数-1只要有一个满足边数> 结点数-1原图就有环将P个连通分量的不等式相加,就得到:P1:E1=M1-1P2:E2=M2-1...PN:EN>MN-1所有边数(E) > 所有结点数(M) - 连通分量个数(P)即: E + P > M 所以只要判断结果 E + P > M 就表示原图有环,否则无环.实例代码如下:1.#include<iostream>2.#include<malloc.h>ing namespace std;4.#define maxNum 100 //定义邻接举证的最大定点数5.int visited[maxNum];//通过visited数组来标记这个顶点是否被访问过,0表示未被访问,1表示被访问6.int DFS_Count;//连通部件个数,用于测试无向图是否连通,DFS_Count=1表示只有一个连通部件,所以整个无向图是连通的7.int pre[maxNum];8.int post[maxNum];9.int point;//pre和post的值10.11.//图的邻接矩阵表示结构12.typedef struct13.{14.char v[maxNum];//图的顶点信息15.int e[maxNum][maxNum];//图的顶点信息16.int vNum;//顶点个数17.int eNum;//边的个数18.}graph;19.void createGraph(graph *g);//创建图g20.void DFS(graph *g);//深度优先遍历图g21.void dfs(graph *g,int i);//从顶点i开始深度优先遍历与其相邻的点22.void dfs(graph *g,int i)23.{24.//cout<<"顶点"<<g->v[i]<<"已经被访问"<<endl;25. cout<<"顶点"<<i<<"已经被访问"<<endl;26. visited[i]=1;//标记顶点i被访问27. pre[i]=++point;28.for(int j=1;j<=g->vNum;j++)29. {30.if(g->e[i][j]!=0&&visited[j]==0)31. dfs(g,j);32. }33. post[i]=++point;34.}35.36.void DFS(graph *g)37.{38.int i;39.//初始化visited数组,表示一开始所有顶点都未被访问过40.for(i=1;i<=g->vNum;i++)41. {42. visited[i]=0;43. pre[i]=0;44. post[i]=0;45. }46.//初始化pre和post47. point=0;48.//初始化连通部件数为049. DFS_Count=0;50.//深度优先搜索51.for(i=1;i<=g->vNum;i++)52. {53.if(visited[i]==0)//如果这个顶点为被访问过,则从i顶点出发进行深度优先遍历54. {55. DFS_Count++;//统计调用void dfs(graph *g,int i);的次数56. dfs(g,i);57. }58. }59.}60.void createGraph(graph *g)//创建图g61.{62. cout<<"正在创建无向图..."<<endl;63. cout<<"请输入顶点个数vNum:";64. cin>>g->vNum;65. cout<<"请输入边的个数eNum:";66. cin>>g->eNum;67.int i,j;68.//输入顶点信息69.//cout<<"请输入顶点信息:"<<endl;70.//for(i=0;i<g->vNum;i++)71.// cin>>g->v[i];72.//初始画图g73.for(i=1;i<=g->vNum;i++)74.for(j=1;j<=g->vNum;j++)75. g->e[i][j]=0;76.//输入边的情况77. cout<<"请输入边的头和尾"<<endl;78.for(int k=0;k<g->eNum;k++)79. {80. cin>>i>>j;81. g->e[i][j]=1;82. g->e[j][i]=1;//无向图对称83. }84.}85.int main()86.{87. graph *g;88. g=(graph*)malloc(sizeof(graph));89. createGraph(g);//创建图g90. DFS(g);//深度优先遍历91.//连通部件数,用于判断是否连通图92. cout<<"连通部件数量:";93. cout<<DFS_Count<<endl;94.if(DFS_Count==1)95. cout<<"图g是连通图"<<endl;96.else if(DFS_Count>1)97. cout<<"图g不是连通图"<<endl;98.//各顶点的pre和post值99.for(int i=1;i<=g->vNum;i++)100. cout<<"顶点"<<i<<"的pre和post分别为:"<<pre[i]<<" "<<post[i]<<endl;101.//cout<<endl;102.//判断无向图中是否有环103.if(g->eNum+DFS_Count>g->vNum)104. cout<<"图g中存在环"<<endl;105.else106. cout<<"图g中不存在环"<<endl;107.int k;108. cin>>k;109.return 0;110.}111./*112.输入:113.正在创建无向图...114.请输入顶点个数vNum:10115.请输入边的个数eNum:9116.请输入边的头和尾117.1 2118.1 4119.2 5120.2 6121.4 7122.5 9123.6 3124.7 8125.9 10126.*/注意:有向图不能使用此方法。

如何判断无向图有环

如何判断无向图有环

如何判断⽆向图有环有向图有⽆环可⽤拓扑排序进⾏检查,当拓扑排序后选出的点不是所有的点集,则该图有环。

但⽆向图⽆法使⽤拓扑排序。

⽆向图可使⽤深度优先搜索来寻找有⽆环,当搜索的当前节点的下⼀个邻接点(当前顶点的⽗顶点不算)已被访问过时,便有环。

可通过简单修改递归DFS的代码来实现判断当前图有⽆环。

1void GraphAdjacencyListWeight::DFSRecursively(int StartVertex) {2int *visited = new int[VertexNumber];3 memset(visited, 0, VertexNumber * sizeof(int));45while (!IsAllVisited(visited)) {6 DFSRecursively(StartVertex, visited, -1);7 }8 }910void GraphAdjacencyListWeight::DFSRecursively(int ver, int *visited, int lastVer) {11 VisitVertex(ver);12 visited[ver] = 1;13for (auto tmpPtr = VectorVertexList[ver]->firstArc; tmpPtr != nullptr; tmpPtr = tmpPtr->nextArc) {14if (visited[tmpPtr->AdjacencyNode] != 1) {15 DFSRecursively(tmpPtr->AdjacencyNode, visited, ver);16 }17else if (tmpPtr->AdjacencyNode != lastVer && lastVer != -1) {18 cout << "有环" << endl;19 }20 }21 }。

判断一个图是否有环 无向图 有向图

判断一个图是否有环 无向图 有向图

一、无向图:方法1:∙如果存在回路,则必存在一个子图,是一个环路。

环路中所有顶点的度>=2。

∙ n算法:第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

如果最后还有未删除顶点,则存在环,否则没有环。

∙ n算法分析:由于有m条边,n个顶点。

i)如果m>=n,则根据图论知识可直接判断存在环路。

(证明:如果没有环路,则该图必然是k棵树k>=1。

根据树的性质,边的数目m = n-k。

k>=1,所以:m<n)ii)如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。

这两种操作的总数不会超过m+n。

由于m<n,所以算法复杂度为O(n)。

∙注:该方法,算法复杂度不止O(V),首先初始时刻统计所有顶点的度的时候,复杂度为(V + E),即使在后来的循环中E>=V,这样算法的复杂度也只能为O(V + E)。

其次,在每次循环时,删除度为1的顶点,那么就必须将与这个顶点相连的点的度减一,并且执行delete node from list[list[node]],这里查找的复杂度为list[list[node]]的长度,只有这样才能保证当degree[i]=1时,list[i]里面只有一个点。

这样最差的复杂度就为O(EV)了。

方法2:DFS搜索图,图中的边只可能是树边或反向边,一旦发现反向边,则表明存在环。

该算法的复杂度为O(V)。

方法3:摘自:/lzrzhao/archive/2008/03/13/2175787.aspx PS:此方法于2011-6-12补充假定:图顶点个数为M,边条数为E遍历一遍,判断图分为几部分(假定为P部分,即图有P 个连通分量)对于每一个连通分量,如果无环则只能是树,即:边数=结点数-1只要有一个满足边数> 结点数-1原图就有环将P个连通分量的不等式相加,就得到:P1:E1=M1-1P2:E2=M2-1...PN:EN>MN-1所有边数(E) > 所有结点数(M) - 连通分量个数(P)即: E + P > M 所以只要判断结果 E + P > M 就表示原图有环,否则无环.实例代码如下:1.#include<iostream>2.#include<malloc.h>ing namespace std;4.#define maxNum 100 //定义邻接举证的最大定点数5.int visited[maxNum];//通过visited数组来标记这个顶点是否被访问过,0表示未被访问,1表示被访问6.int DFS_Count;//连通部件个数,用于测试无向图是否连通,DFS_Count=1表示只有一个连通部件,所以整个无向图是连通的7.int pre[maxNum];8.int post[maxNum];9.int point;//pre和post的值10.11.//图的邻接矩阵表示结构12.typedef struct13.{14.char v[maxNum];//图的顶点信息15.int e[maxNum][maxNum];//图的顶点信息16.int vNum;//顶点个数17.int eNum;//边的个数18.}graph;19.void createGraph(graph *g);//创建图g20.void DFS(graph *g);//深度优先遍历图g21.void dfs(graph *g,int i);//从顶点i开始深度优先遍历与其相邻的点22.void dfs(graph *g,int i)23.{24.//cout<<"顶点"<<g->v[i]<<"已经被访问"<<endl;25. cout<<"顶点"<<i<<"已经被访问"<<endl;26. visited[i]=1;//标记顶点i被访问27. pre[i]=++point;28.for(int j=1;j<=g->vNum;j++)29. {30.if(g->e[i][j]!=0&&visited[j]==0)31. dfs(g,j);32. }33. post[i]=++point;34.}35.36.void DFS(graph *g)37.{38.int i;39.//初始化visited数组,表示一开始所有顶点都未被访问过40.for(i=1;i<=g->vNum;i++)41. {42. visited[i]=0;43. pre[i]=0;44. post[i]=0;45. }46.//初始化pre和post47. point=0;48.//初始化连通部件数为049. DFS_Count=0;50.//深度优先搜索51.for(i=1;i<=g->vNum;i++)52. {53.if(visited[i]==0)//如果这个顶点为被访问过,则从i顶点出发进行深度优先遍历54. {55. DFS_Count++;//统计调用void dfs(graph *g,int i);的次数56. dfs(g,i);57. }58. }59.}60.void createGraph(graph *g)//创建图g61.{62. cout<<"正在创建无向图..."<<endl;63. cout<<"请输入顶点个数vNum:";64. cin>>g->vNum;65. cout<<"请输入边的个数eNum:";66. cin>>g->eNum;67.int i,j;68.//输入顶点信息69.//cout<<"请输入顶点信息:"<<endl;70.//for(i=0;i<g->vNum;i++)71.// cin>>g->v[i];72.//初始画图g73.for(i=1;i<=g->vNum;i++)74.for(j=1;j<=g->vNum;j++)75. g->e[i][j]=0;76.//输入边的情况77. cout<<"请输入边的头和尾"<<endl;78.for(int k=0;k<g->eNum;k++)79. {80. cin>>i>>j;81. g->e[i][j]=1;82. g->e[j][i]=1;//无向图对称83. }84.}85.int main()86.{87. graph *g;88. g=(graph*)malloc(sizeof(graph));89. createGraph(g);//创建图g90. DFS(g);//深度优先遍历91.//连通部件数,用于判断是否连通图92. cout<<"连通部件数量:";93. cout<<DFS_Count<<endl;94.if(DFS_Count==1)95. cout<<"图g是连通图"<<endl;96.else if(DFS_Count>1)97. cout<<"图g不是连通图"<<endl;98.//各顶点的pre和post值99.for(int i=1;i<=g->vNum;i++)100. cout<<"顶点"<<i<<"的pre和post分别为:"<<pre[i]<<" "<<post[i]<<endl;101.//cout<<endl;102.//判断无向图中是否有环103.if(g->eNum+DFS_Count>g->vNum)104. cout<<"图g中存在环"<<endl;105.else106. cout<<"图g中不存在环"<<endl;107.int k;108. cin>>k;109.return 0;110.}111./*112.输入:113.正在创建无向图...114.请输入顶点个数vNum:10115.请输入边的个数eNum:9116.请输入边的头和尾117.1 2118.1 4119.2 5120.2 6121.4 7122.5 9123.6 3124.7 8125.9 10126.*/注意:有向图不能使用此方法。

无向图判断回路

无向图判断回路

关于无向图判断是否存在回路的方法:基本思路有三种:第一种是类似有向图拓扑排序的思路:(参考有向图判断回路的解答)如果存在回路,则必存在一个子图,是一个环。

因此该子图中所有顶点入度>=1。

算法:在有向图中,先找出入度为0的顶点,删除与这个顶点相关联的边(出边),将与这些边相关的其它顶点的入度减1,循环直到没有入度为0的定点。

如果此时还有未被删除顶点,则必存在环路,否则不存在环路。

无向图则可以转化为:如果存在回路,则必存在一个子图,是一个环路。

因此环路中所有顶点的度>=2。

算法:第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

如果最后还有未删除顶点,则存在环,否则没有环。

算法分析:由于有m条边,n个顶点。

如果m>=n,则根据图论知识可直接判断存在环路。

(证明:如果没有环路,则该图必然是k棵树k>=1。

根据树的性质,边的数目m = n-k。

k>=1,所以:m<n)如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。

这两种操作的总数不会超过m+n。

由于m<n,所以算法复杂度为O(n)第二种为借助广度优先的策略:任选一个顶点进行广度优先搜索。

由于广度优先的算法本质就是从一个顶点出发将图按距离该顶点的远近层层展开为树形结构,如果存在某个顶点被访问两次表明树形展开层次结构中存在回边,因此则必存在回路。

一种比较直接的思路是:为了要判断是否存在环路,需要在每个新近被加入访问队列的顶点上记录下该顶点的上一步的父顶点是哪一个,除了父顶点外其它相关顶点可以加入广度优先算法的队列,并将所有入队顶点的访问次数加一。

如果发现访问次数>1的情况,则存在回路。

反之,如果算法结束没有访问次数>1的情况则不存在回路。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、无向图:方法1:∙如果存在回路,则必存在一个子图,是一个环路。

环路中所有顶点的度>=2。

∙ n算法:第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

如果最后还有未删除顶点,则存在环,否则没有环。

∙ n算法分析:由于有m条边,n个顶点。

i)如果m>=n,则根据图论知识可直接判断存在环路。

(证明:如果没有环路,则该图必然是k棵树k>=1。

根据树的性质,边的数目m = n-k。

k>=1,所以:m<n)ii)如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。

这两种操作的总数不会超过m+n。

由于m<n,所以算法复杂度为O(n)。

∙注:该方法,算法复杂度不止O(V),首先初始时刻统计所有顶点的度的时候,复杂度为(V + E),即使在后来的循环中E>=V,这样算法的复杂度也只能为O(V + E)。

其次,在每次循环时,删除度为1的顶点,那么就必须将与这个顶点相连的点的度减一,并且执行delete node from list[list[node]],这里查找的复杂度为list[list[node]]的长度,只有这样才能保证当degree[i]=1时,list[i]里面只有一个点。

这样最差的复杂度就为O(EV)了。

方法2:DFS搜索图,图中的边只可能是树边或反向边,一旦发现反向边,则表明存在环。

该算法的复杂度为O(V)。

方法3:摘自:/lzrzhao/archive/2008/03/13/2175787.aspx PS:此方法于2011-6-12补充假定:图顶点个数为M,边条数为E遍历一遍,判断图分为几部分(假定为P部分,即图有P 个连通分量)对于每一个连通分量,如果无环则只能是树,即:边数=结点数-1只要有一个满足边数> 结点数-1原图就有环将P个连通分量的不等式相加,就得到:P1:E1=M1-1P2:E2=M2-1...PN:EN>MN-1所有边数(E) > 所有结点数(M) - 连通分量个数(P)即: E + P > M 所以只要判断结果 E + P > M 就表示原图有环,否则无环.实例代码如下:1.#include<iostream>2.#include<malloc.h>ing namespace std;4.#define maxNum 100 //定义邻接举证的最大定点数5.int visited[maxNum];//通过visited数组来标记这个顶点是否被访问过,0表示未被访问,1表示被访问6.int DFS_Count;//连通部件个数,用于测试无向图是否连通,DFS_Count=1表示只有一个连通部件,所以整个无向图是连通的7.int pre[maxNum];8.int post[maxNum];9.int point;//pre和post的值10.11.//图的邻接矩阵表示结构12.typedef struct13.{14.char v[maxNum];//图的顶点信息15.int e[maxNum][maxNum];//图的顶点信息16.int vNum;//顶点个数17.int eNum;//边的个数18.}graph;19.void createGraph(graph *g);//创建图g20.void DFS(graph *g);//深度优先遍历图g21.void dfs(graph *g,int i);//从顶点i开始深度优先遍历与其相邻的点22.void dfs(graph *g,int i)23.{24.//cout<<"顶点"<<g->v[i]<<"已经被访问"<<endl;25. cout<<"顶点"<<i<<"已经被访问"<<endl;26. visited[i]=1;//标记顶点i被访问27. pre[i]=++point;28.for(int j=1;j<=g->vNum;j++)29. {30.if(g->e[i][j]!=0&&visited[j]==0)31. dfs(g,j);32. }33. post[i]=++point;34.}35.36.void DFS(graph *g)37.{38.int i;39.//初始化visited数组,表示一开始所有顶点都未被访问过40.for(i=1;i<=g->vNum;i++)41. {42. visited[i]=0;43. pre[i]=0;44. post[i]=0;45. }46.//初始化pre和post47. point=0;48.//初始化连通部件数为049. DFS_Count=0;50.//深度优先搜索51.for(i=1;i<=g->vNum;i++)52. {53.if(visited[i]==0)//如果这个顶点为被访问过,则从i顶点出发进行深度优先遍历54. {55. DFS_Count++;//统计调用void dfs(graph *g,int i);的次数56. dfs(g,i);57. }58. }59.}60.void createGraph(graph *g)//创建图g61.{62. cout<<"正在创建无向图..."<<endl;63. cout<<"请输入顶点个数vNum:";64. cin>>g->vNum;65. cout<<"请输入边的个数eNum:";66. cin>>g->eNum;67.int i,j;68.//输入顶点信息69.//cout<<"请输入顶点信息:"<<endl;70.//for(i=0;i<g->vNum;i++)71.// cin>>g->v[i];72.//初始画图g73.for(i=1;i<=g->vNum;i++)74.for(j=1;j<=g->vNum;j++)75. g->e[i][j]=0;76.//输入边的情况77. cout<<"请输入边的头和尾"<<endl;78.for(int k=0;k<g->eNum;k++)79. {80. cin>>i>>j;81. g->e[i][j]=1;82. g->e[j][i]=1;//无向图对称83. }84.}85.int main()86.{87. graph *g;88. g=(graph*)malloc(sizeof(graph));89. createGraph(g);//创建图g90. DFS(g);//深度优先遍历91.//连通部件数,用于判断是否连通图92. cout<<"连通部件数量:";93. cout<<DFS_Count<<endl;94.if(DFS_Count==1)95. cout<<"图g是连通图"<<endl;96.else if(DFS_Count>1)97. cout<<"图g不是连通图"<<endl;98.//各顶点的pre和post值99.for(int i=1;i<=g->vNum;i++)100. cout<<"顶点"<<i<<"的pre和post分别为:"<<pre[i]<<" "<<post[i]<<endl;101.//cout<<endl;102.//判断无向图中是否有环103.if(g->eNum+DFS_Count>g->vNum)104. cout<<"图g中存在环"<<endl;105.else106. cout<<"图g中不存在环"<<endl;107.int k;108. cin>>k;109.return 0;110.}111./*112.输入:113.正在创建无向图...114.请输入顶点个数vNum:10115.请输入边的个数eNum:9116.请输入边的头和尾117.1 2118.1 4119.2 5120.2 6121.4 7122.5 9123.6 3124.7 8125.9 10126.*/注意:有向图不能使用此方法。

比如1->2,1-3,2->3,4->5,如果使用上述方法会判定为含有还,但并非如此。

二、有向图:主要有深度优先和拓扑排序2中方法1、拓扑排序,如果能够用拓扑排序完成对图中所有节点的排序的话,就说明这个图中没有环,而如果不能完成,则说明有环。

2、可以用Strongly Connected Components来做,我们可以回忆一下强连通子图的概念,就是说对于一个图的某个子图,该子图中的任意u->v,必有v->u,则这是一个强连通子图。

这个限定正好是环的概念。

所以我想,通过寻找图的强连通子图的方法应该可以找出一个图中到底有没有环、有几个环。

3、就是用一个改进的DFS刚看到这个问题的时候,我想单纯用DFS就可以解决问题了。

但细想一下,是不能够的。

如果题目给出的是一个无向图,那么OK,DFS是可以解决的。

但无向图得不出正确结果的。

比如:A->B,A->C->B,我们用DFS来处理这个图,我们会得出它有环,但其实没有。

我们可以对DFS稍加变化,来解决这个问题。

解决的方法如下:图中的一个节点,根据其C[N]的值,有三种状态:0,此节点没有被访问过-1,被访问过至少1次,其后代节点正在被访问中1,其后代节点都被访问过。

相关文档
最新文档