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

在一些经典算法中,经常需要判断一些图是否具有环路,比如拓扑排序,需要在最初判断该图是否有环路,如有有环路,则无法找到最长的一条线,比如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;//辅助变量,判断这个点是否入度为0
					for(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 4
1 2 1
1 3 1
2 3 1
4 5 1

5 4
1 2 1
2 1 1
2 3 1
4 5 1

实验结果:

  

时间: 2024-10-13 16:22:39

算法之判断一个图是否有环的相关文章

(转)判断一个图是否有环 无向图 有向图

无向图: 法1: 如果存在回路,则必存在一个子图,是一个环路.环路中所有顶点的度>=2. n算法: 第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一. 第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一. 如果最后还有未删除顶点,则存在环,否则没有环. n算法分析: 由于有m条边,n个顶点.如果m>=n,则根据图论知识可直接判断存在环路. (证明:如果没有环路,则该图必然是k棵树 k>=1.根据树的性质,边的数目m = n-k.k

判断一个图是否有环 无向图 有向图(转)

没有找到原文出处,请参考一下链接: http://www.cnblogs.com/hiside/archive/2010/12/01/1893878.html http://topic.csdn.net/u/20071023/11/3edb81fc-37b2-4506-906e-44dc0fc521f2.html 一.无向图: 方法1: 如果存在回路,则必存在一个子图,是一个环路.环路中所有顶点的度>=2. n算法: 第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度

【C++】判断一个图是否有环 无向图 有向图(转载)

没有找到原文出处,请参考一下链接: http://www.cnblogs.com/hiside/archive/2010/12/01/1893878.html http://topic.csdn.net/u/20071023/11/3edb81fc-37b2-4506-906e-44dc0fc521f2.html 一.无向图: 方法1: 如果存在回路,则必存在一个子图,是一个环路.环路中所有顶点的度>=2. n算法: 第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度

经典算法之判断一个整数是否为素数

经典算法之判断一个整数是否为素数 1 /** 2 判断一个数是否为素数 如: 3 输入: 任意一个数 12 4 输出: 1或0(1表示为素数) 0 5 */ 6 /**************被称为笨蛋的做法************/ 7 #include <stdio.h> 8 9 int main() 10 { 11 12 int i,n; //i为计数数,n为存储用户输入的数 13 14 do //循环检测用户输入的数据>0为合法 15 scanf("%d",&

并查集(判断一个图有几个连通块)

import java.util.Scanner; // 并查集 判断一个图中有几个联通块 public class UnionFind { private int[] father;// private int count;// 分量数量 public UnionFind(int N){ count=N; father=new int[N]; for(int i=0;i<N;i++){ father[i]=i; } } public int count() { return count; }

如何判断一个图中是否存在环路

最近公司的项目中,有个树形结构变图结构的问题.本来我们对项目中实体之间的关系是按树形结构来表示的,也就是说实体之间不会重用,也不会有环.现在我们需要变成图的结构,实体之间可以重用,但不能有环.那么该如何解决这个问题呢? 我们先定义出什么是环: 环定义:从一条边出发,如果能回到当前边则证明有环. 可见,根据定义,上面的图不存在环.因为从任意一条边出发都不可能回到自身.下面给出一个带有环的图. 图中红色箭头的3,4,5构成了一个环路.因为从3.4.5任一点出发,都可以回到起始点.那么我们如何使用代码

poj Transferring Sylla(如何快速的判断一个图是否是3—连通图,求割点,割边)

Transferring Sylla 首先,什么是k连通图?k连通图就是指至少去掉k个点使之不连通的图. 题目: 题目描述的很裸,就是给你一张图要求你判断这图是否是3-连通图. 算法分析: ///////////////////////////////////////////////////////////////////// (网上别人的分析,分析的很好所以直接引用了) 考虑一下不可行的情况,就是存在两点间的路径条数<3情况,那么我们可以去枚举两个点a和b,然后将其和相邻的边删除,然后判断联通

判断一个链表是否有环

思路:如果开始有两个指针指向头结点,一个走的快,一个走的慢,如果有环的话,最终经过若干步,快的指针总会超过慢的指针一圈从而相遇. 如何计算环的长度呢?可以第一次相遇时开始计数,第二次相遇时停止计数. 如何判断环的入口点?碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点.头指针开始走,相遇的那个点就是连接点. 当fast与slow相遇时,show肯定没有走完链表,而fast已经在还里走了n(n>= 1)圈.假设slow走了s步,那么fast走了2s步.fast的步数还等于s走的加上

判断一个图中有无环路的存在

这里要引入两个概念: 1.树边:是一条未被遍历过的边,它指向一个未被访问过的点. 2.反向边:是一条未被遍历过的边,它指向一个被访问过的点. 如果图中有环路的存在,那么环路的最后一个边必然是一条反向边. 我的参考 那么,我们在DFS遍历的过程当中,只需要添加一条语句来判断所有未被检查过的边的指向点是否已被访问过,就可以判断出这个图是否存在环路了. 1 struct Edge { 2 int to, w, next; 3 }; 4 5 struct adjTable { 6 int node[ma